]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #106175 - compiler-errors:bad-import-sugg, r=oli-obk
authorYuki Okushi <huyuumi.dev+love@gmail.com>
Mon, 9 Jan 2023 23:05:34 +0000 (08:05 +0900)
committerGitHub <noreply@github.com>
Mon, 9 Jan 2023 23:05:34 +0000 (08:05 +0900)
Fix bad import suggestion with nested `use` tree

Fixes #105566
Fixes #105373

Ideally, we'd find some way to turn these into structured suggestions -- perhaps on a separate line as a different `use` statement, but I have no idea how to access the span for the whole `use` from this point in the import resolution code.

1660 files changed:
Cargo.lock
Cargo.toml
README.md
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/ast_traits.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/expand/allocator.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/token.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/literal.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/lifetime_collector.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/item.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_attr/src/session_diagnostics.rs
compiler/rustc_borrowck/src/borrowck_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/diagnostics/var_name.rs
compiler/rustc_borrowck/src/facts.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_borrowck/src/type_check/input_output.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/deriving/debug.rs
compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
compiler/rustc_builtin_macros/src/env.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/proc_macro_harness.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/context.rs
compiler/rustc_codegen_llvm/src/abi.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/common.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/errors.rs
compiler/rustc_codegen_ssa/src/mir/constant.rs
compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
compiler/rustc_const_eval/src/transform/check_consts/mod.rs
compiler/rustc_data_structures/src/graph/dominators/mod.rs
compiler/rustc_data_structures/src/graph/scc/mod.rs
compiler/rustc_data_structures/src/obligation_forest/graphviz.rs
compiler/rustc_data_structures/src/profiling.rs
compiler/rustc_data_structures/src/small_c_str.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/vec_map.rs
compiler/rustc_driver/src/args.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0015.md
compiler/rustc_error_codes/src/error_codes/E0208.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0461.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0514.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0519.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0588.md
compiler/rustc_error_codes/src/error_codes/E0640.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0711.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0717.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0729.md
compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
compiler/rustc_error_messages/locales/en-US/infer.ftl
compiler/rustc_error_messages/locales/en-US/metadata.ftl
compiler/rustc_error_messages/locales/en-US/parse.ftl
compiler/rustc_error_messages/locales/en-US/session.ftl
compiler/rustc_errors/Cargo.toml
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_errors/src/lib.rs
compiler/rustc_expand/src/build.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/mbe/diagnostics.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_feature/src/lib.rs
compiler/rustc_graphviz/src/lib.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/bounds.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/compare_impl_item.rs [new file with mode: 0644]
compiler/rustc_hir_analysis/src/check/compare_method.rs [deleted file]
compiler/rustc_hir_analysis/src/check/mod.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/coherence/orphan.rs
compiler/rustc_hir_analysis/src/coherence/unsafety.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/generics_of.rs
compiler/rustc_hir_analysis/src/collect/item_bounds.rs
compiler/rustc_hir_analysis/src/collect/lifetimes.rs
compiler/rustc_hir_analysis/src/collect/predicates_of.rs
compiler/rustc_hir_analysis/src/collect/type_of.rs
compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_hir_typeck/src/_match.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/expr.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/gather_locals.rs
compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
compiler/rustc_hir_typeck/src/lib.rs
compiler/rustc_hir_typeck/src/method/confirm.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/prelude2021.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_hir_typeck/src/op.rs
compiler/rustc_hir_typeck/src/pat.rs
compiler/rustc_hir_typeck/src/place_op.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_index/src/interval.rs
compiler/rustc_infer/src/errors/mod.rs
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/error_reporting/note_region.rs [deleted file]
compiler/rustc_infer/src/infer/error_reporting/suggest.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/note.rs [deleted file]
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_interface/src/callbacks.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lexer/src/lib.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/pass_by_value.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_llvm/build.rs
compiler/rustc_log/src/lib.rs
compiler/rustc_macros/src/diagnostics/error.rs
compiler/rustc_macros/src/diagnostics/fluent.rs
compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
compiler/rustc_macros/src/diagnostics/utils.rs
compiler/rustc_macros/src/newtype.rs
compiler/rustc_macros/src/query.rs
compiler/rustc_macros/src/symbols.rs
compiler/rustc_macros/src/symbols/tests.rs
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/dependency_format.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/def_path_hash_map.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/lint.rs
compiler/rustc_middle/src/macros.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/query.rs
compiler/rustc_middle/src/ty/erase_regions.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/typeck_results.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/visit.rs
compiler/rustc_middle/src/ty/walk.rs
compiler/rustc_middle/src/util/bug.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_dataflow/src/framework/direction.rs
compiler/rustc_mir_dataflow/src/framework/fmt.rs
compiler/rustc_mir_dataflow/src/framework/graphviz.rs
compiler/rustc_mir_dataflow/src/move_paths/mod.rs
compiler/rustc_mir_dataflow/src/value_analysis.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/dead_store_elimination.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_monomorphize/Cargo.toml
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/errors.rs
compiler/rustc_monomorphize/src/partitioning/mod.rs
compiler/rustc_monomorphize/src/util.rs
compiler/rustc_parse/src/errors.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.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/hir_stats.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/Cargo.toml
compiler/rustc_query_impl/src/lib.rs
compiler/rustc_query_impl/src/on_disk_cache.rs
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_impl/src/profiling_support.rs
compiler/rustc_query_system/src/dep_graph/debug.rs
compiler/rustc_query_system/src/dep_graph/dep_node.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/errors.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/edition.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/profiling.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/span_encoding.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/legacy.rs
compiler/rustc_symbol_mangling/src/lib.rs
compiler/rustc_symbol_mangling/src/test.rs
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/asm/aarch64.rs
compiler/rustc_target/src/asm/arm.rs
compiler/rustc_target/src/asm/mod.rs
compiler/rustc_target/src/asm/x86.rs
compiler/rustc_target/src/spec/aarch64_fuchsia.rs [deleted file]
compiler/rustc_target/src/spec/aarch64_unknown_fuchsia.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/bpf_base.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/solid_base.rs
compiler/rustc_target/src/spec/x86_64_fuchsia.rs [deleted file]
compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/infer.rs
compiler/rustc_trait_selection/src/solve/overflow.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/engine.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/util.rs
compiler/rustc_traits/src/dropck_outlives.rs
compiler/rustc_traits/src/normalize_erasing_regions.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_transmute/src/layout/mod.rs
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/layout.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_type_ir/src/sty.rs
library/alloc/Cargo.toml
library/alloc/benches/slice.rs
library/alloc/src/alloc.rs
library/alloc/src/boxed.rs
library/alloc/src/boxed/thin.rs
library/alloc/src/collections/binary_heap/tests.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/mod.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/collections/btree/set/tests.rs
library/alloc/src/collections/btree/testing/crash_test.rs [deleted file]
library/alloc/src/collections/btree/testing/mod.rs [deleted file]
library/alloc/src/collections/btree/testing/ord_chaos.rs [deleted file]
library/alloc/src/collections/btree/testing/rng.rs [deleted file]
library/alloc/src/collections/linked_list/tests.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/slice.rs
library/alloc/src/slice/tests.rs [new file with mode: 0644]
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/testing/crash_test.rs [new file with mode: 0644]
library/alloc/src/testing/mod.rs [new file with mode: 0644]
library/alloc/src/testing/ord_chaos.rs [new file with mode: 0644]
library/alloc/src/testing/rng.rs [new file with mode: 0644]
library/alloc/src/vec/mod.rs
library/alloc/tests/autotraits.rs
library/alloc/tests/slice.rs
library/core/Cargo.toml
library/core/benches/num/int_log/mod.rs
library/core/src/any.rs
library/core/src/cell.rs
library/core/src/cell/lazy.rs
library/core/src/cell/once.rs
library/core/src/char/methods.rs
library/core/src/char/mod.rs
library/core/src/cmp.rs
library/core/src/const_closure.rs
library/core/src/fmt/mod.rs
library/core/src/future/future.rs
library/core/src/future/mod.rs
library/core/src/intrinsics.rs
library/core/src/intrinsics/mir.rs
library/core/src/iter/sources/empty.rs
library/core/src/iter/sources/once_with.rs
library/core/src/iter/sources/repeat_n.rs
library/core/src/iter/sources/repeat_with.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/marker.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/int_macros.rs
library/core/src/num/nonzero.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/function.rs
library/core/src/panic.rs
library/core/src/panic/panic_info.rs
library/core/src/panicking.rs
library/core/src/prelude/mod.rs
library/core/src/prelude/v1.rs
library/core/src/ptr/alignment.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/metadata.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/sort.rs
library/core/src/str/iter.rs
library/core/src/str/mod.rs
library/core/src/task/poll.rs
library/core/src/task/wake.rs
library/core/src/unicode/mod.rs
library/core/tests/any.rs
library/core/tests/lazy.rs
library/core/tests/lib.rs
library/core/tests/mem.rs
library/core/tests/num/flt2dec/random.rs
library/core/tests/ptr.rs
library/core/tests/slice.rs
library/core/tests/str.rs
library/core/tests/task.rs
library/panic_abort/src/lib.rs
library/panic_unwind/src/lib.rs
library/proc_macro/src/bridge/client.rs
library/proc_macro/src/bridge/fxhash.rs
library/proc_macro/src/bridge/server.rs
library/rustc-std-workspace-alloc/lib.rs
library/std/Cargo.toml
library/std/src/alloc.rs
library/std/src/backtrace.rs
library/std/src/collections/hash/map/tests.rs
library/std/src/collections/hash/set.rs
library/std/src/fs/tests.rs
library/std/src/io/error/repr_bitpacked.rs
library/std/src/io/mod.rs
library/std/src/io/stdio.rs
library/std/src/lib.rs
library/std/src/macros.rs
library/std/src/net/ip_addr.rs
library/std/src/panic.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/prelude/v1.rs
library/std/src/process.rs
library/std/src/process/tests.rs
library/std/src/rt.rs
library/std/src/sync/lazy_lock.rs
library/std/src/sync/lazy_lock/tests.rs
library/std/src/sync/mod.rs
library/std/src/sync/mpmc/utils.rs
library/std/src/sync/once_lock.rs
library/std/src/sync/remutex.rs [new file with mode: 0644]
library/std/src/sync/remutex/tests.rs [new file with mode: 0644]
library/std/src/sync/rwlock/tests.rs
library/std/src/sys/itron/thread.rs
library/std/src/sys/sgx/mod.rs
library/std/src/sys/sgx/thread.rs
library/std/src/sys/sgx/thread_parker.rs [deleted file]
library/std/src/sys/sgx/thread_parking.rs [new file with mode: 0644]
library/std/src/sys/unix/android.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/net.rs
library/std/src/sys/unix/process/process_common.rs
library/std/src/sys/unix/thread.rs
library/std/src/sys/unix/thread_parker/darwin.rs [deleted file]
library/std/src/sys/unix/thread_parker/mod.rs [deleted file]
library/std/src/sys/unix/thread_parker/netbsd.rs [deleted file]
library/std/src/sys/unix/thread_parker/pthread.rs [deleted file]
library/std/src/sys/unix/thread_parking/darwin.rs [new file with mode: 0644]
library/std/src/sys/unix/thread_parking/mod.rs [new file with mode: 0644]
library/std/src/sys/unix/thread_parking/netbsd.rs [new file with mode: 0644]
library/std/src/sys/unix/thread_parking/pthread.rs [new file with mode: 0644]
library/std/src/sys/unix/weak.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys/windows/thread_parker.rs [deleted file]
library/std/src/sys/windows/thread_parking.rs [new file with mode: 0644]
library/std/src/sys_common/backtrace.rs
library/std/src/sys_common/io.rs
library/std/src/sys_common/mod.rs
library/std/src/sys_common/process.rs
library/std/src/sys_common/remutex.rs [deleted file]
library/std/src/sys_common/remutex/tests.rs [deleted file]
library/std/src/sys_common/thread_local_key.rs
library/std/src/sys_common/thread_parker/futex.rs [deleted file]
library/std/src/sys_common/thread_parker/generic.rs [deleted file]
library/std/src/sys_common/thread_parker/mod.rs [deleted file]
library/std/src/sys_common/thread_parker/wait_flag.rs [deleted file]
library/std/src/sys_common/thread_parking/futex.rs [new file with mode: 0644]
library/std/src/sys_common/thread_parking/generic.rs [new file with mode: 0644]
library/std/src/sys_common/thread_parking/id.rs [new file with mode: 0644]
library/std/src/sys_common/thread_parking/mod.rs [new file with mode: 0644]
library/std/src/sys_common/thread_parking/wait_flag.rs [new file with mode: 0644]
library/std/src/thread/local.rs
library/std/src/thread/mod.rs
library/std/tests/env.rs
library/std/tests/run-time-detect.rs
library/test/src/console.rs
library/test/src/formatters/json.rs
library/test/src/formatters/junit.rs
library/test/src/formatters/pretty.rs
library/test/src/formatters/terse.rs
library/test/src/lib.rs
library/test/src/term/terminfo/mod.rs
library/test/src/term/terminfo/parm.rs
library/test/src/term/terminfo/searcher.rs
library/test/src/test_result.rs
library/test/src/types.rs
library/unwind/src/libunwind.rs
src/bootstrap/CHANGELOG.md
src/bootstrap/Cargo.lock
src/bootstrap/Cargo.toml
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/clean.rs
src/bootstrap/compile.rs
src/bootstrap/configure.py
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/download-ci-llvm-stamp
src/bootstrap/flags.rs
src/bootstrap/format.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/run.rs
src/bootstrap/setup.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/ci/docker/host-x86_64/dist-various-2/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/build-fuchsia-toolchain.sh
src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
src/ci/docker/scripts/fuchsia-test-runner.py
src/ci/run.sh
src/doc/book
src/doc/nomicon
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/armv7-sony-vita-eabihf.md [new file with mode: 0644]
src/doc/rustc/src/platform-support/fuchsia.md
src/doc/rustc/src/targets/index.md
src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/dump-mono-stats.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/etc/pre-push.sh
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/fold.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/search_index.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/js/main.js
src/librustdoc/html/templates/page.html
src/librustdoc/json/conversions.rs
src/librustdoc/passes/check_doc_test_visibility.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/visit.rs
src/librustdoc/visit_ast.rs
src/llvm-project
src/rustdoc-json-types/lib.rs
src/stage0.json
src/test/assembly/stack-protector/stack-protector-target-support.rs
src/test/codegen/box-maybe-uninit-llvm14.rs
src/test/codegen/box-maybe-uninit.rs
src/test/codegen/function-arguments.rs
src/test/codegen/issue-103840.rs [new file with mode: 0644]
src/test/codegen/issue-86106.rs [new file with mode: 0644]
src/test/codegen/noalias-flag.rs [new file with mode: 0644]
src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
src/test/codegen/zst-offset.rs
src/test/incremental/change_symbol_export_status.rs
src/test/incremental/hashes/call_expressions.rs
src/test/incremental/hashes/closure_expressions.rs
src/test/incremental/hashes/enum_constructors.rs
src/test/incremental/hashes/enum_defs.rs
src/test/incremental/hashes/exported_vs_not.rs
src/test/incremental/hashes/extern_mods.rs
src/test/incremental/hashes/for_loops.rs
src/test/incremental/hashes/function_interfaces.rs
src/test/incremental/hashes/if_expressions.rs
src/test/incremental/hashes/indexing_expressions.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/inline_asm.rs
src/test/incremental/hashes/let_expressions.rs
src/test/incremental/hashes/loop_expressions.rs
src/test/incremental/hashes/match_expressions.rs
src/test/incremental/hashes/statics.rs
src/test/incremental/hashes/struct_constructors.rs
src/test/incremental/hashes/struct_defs.rs
src/test/incremental/hashes/trait_defs.rs
src/test/incremental/hashes/trait_impls.rs
src/test/incremental/hashes/unary_and_binary_exprs.rs
src/test/incremental/hashes/while_let_loops.rs
src/test/incremental/hashes/while_loops.rs
src/test/incremental/spans_significant_w_debuginfo.rs
src/test/incremental/spans_significant_w_panic.rs
src/test/incremental/string_constant.rs
src/test/incremental/thinlto/cgu_keeps_identical_fn.rs
src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation.rs
src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation2.rs
src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation3.rs
src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/mutable_variable.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir [new file with mode: 0644]
src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir [new file with mode: 0644]
src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir [deleted file]
src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir [deleted file]
src/test/mir-opt/const_prop/optimizes_into_variable.rs
src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
src/test/mir-opt/const_prop/ref_deref.rs
src/test/mir-opt/const_prop/ref_deref_project.rs
src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/slice_len.rs
src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
src/test/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff
src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
src/test/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.mir
src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
src/test/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/div_overflow.rs [new file with mode: 0644]
src/test/mir-opt/inline/cycle.g.Inline.diff
src/test/mir-opt/inline/cycle.main.Inline.diff
src/test/mir-opt/inline/exponential_runtime.main.Inline.diff
src/test/mir-opt/inline/inline_cycle.one.Inline.diff
src/test/mir-opt/inline/inline_cycle.two.Inline.diff
src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/inline/inline_generator.main.Inline.diff
src/test/mir-opt/inline/inline_shims.clone.Inline.diff
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
src/test/mir-opt/issue_101973.inner.ConstProp.diff
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/simple_option_map_e2e.rs [new file with mode: 0644]
src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
src/test/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.d1.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.d2.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.r.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.rs
src/test/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals_fixedpoint.rs
src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals_removes_unused_consts.rs
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff [new file with mode: 0644]
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.rs
src/test/mir-opt/simplify_match.main.ConstProp.diff
src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir [new file with mode: 0644]
src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir [deleted file]
src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir [new file with mode: 0644]
src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir [deleted file]
src/test/mir-opt/uninhabited_enum.rs
src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
src/test/run-make-fulldeps/save-analysis/foo.rs
src/test/run-make/dump-mono-stats/Makefile [new file with mode: 0644]
src/test/run-make/dump-mono-stats/foo.rs [new file with mode: 0644]
src/test/rustdoc-gui/anchors.goml
src/test/rustdoc-gui/code-color.goml
src/test/rustdoc-gui/codeblock-tooltip.goml
src/test/rustdoc-gui/docblock-code-block-line-number.goml
src/test/rustdoc-gui/docblock-table.goml
src/test/rustdoc-gui/escape-key.goml
src/test/rustdoc-gui/headers-color.goml
src/test/rustdoc-gui/headings.goml
src/test/rustdoc-gui/help-page.goml
src/test/rustdoc-gui/highlight-colors.goml
src/test/rustdoc-gui/impl-doc.goml
src/test/rustdoc-gui/implementors.goml
src/test/rustdoc-gui/item-decl-colors.goml
src/test/rustdoc-gui/jump-to-def-background.goml
src/test/rustdoc-gui/links-color.goml
src/test/rustdoc-gui/mobile.goml
src/test/rustdoc-gui/notable-trait.goml
src/test/rustdoc-gui/run-on-hover.goml
src/test/rustdoc-gui/rust-logo.goml
src/test/rustdoc-gui/scrape-examples-button-focus.goml
src/test/rustdoc-gui/scrape-examples-color.goml [new file with mode: 0644]
src/test/rustdoc-gui/scrape-examples-fonts.goml
src/test/rustdoc-gui/scrape-examples-layout.goml
src/test/rustdoc-gui/scrape-examples-toggle.goml
src/test/rustdoc-gui/search-filter.goml
src/test/rustdoc-gui/search-no-result.goml
src/test/rustdoc-gui/search-result-color.goml
src/test/rustdoc-gui/search-result-display.goml
src/test/rustdoc-gui/search-tab.goml [new file with mode: 0644]
src/test/rustdoc-gui/sidebar-links-color.goml
src/test/rustdoc-gui/sidebar-mobile.goml
src/test/rustdoc-gui/sidebar-source-code-display.goml
src/test/rustdoc-gui/sidebar-source-code.goml
src/test/rustdoc-gui/sidebar.goml
src/test/rustdoc-gui/source-code-page.goml
src/test/rustdoc-gui/src/lib2/Cargo.lock
src/test/rustdoc-gui/src/lib2/Cargo.toml
src/test/rustdoc-gui/src/lib2/http/Cargo.toml [new file with mode: 0644]
src/test/rustdoc-gui/src/lib2/http/lib.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml
src/test/rustdoc-gui/src/lib2/implementors/lib.rs
src/test/rustdoc-gui/stab-badge.goml
src/test/rustdoc-gui/target.goml
src/test/rustdoc-gui/toggle-docs.goml
src/test/rustdoc-gui/type-declation-overflow.goml
src/test/rustdoc-gui/unsafe-fn.goml
src/test/rustdoc-json/doc_hidden_failure.rs
src/test/rustdoc-json/enums/discriminant/basic.rs
src/test/rustdoc-json/enums/discriminant/expr.rs
src/test/rustdoc-json/enums/discriminant/limits.rs
src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
src/test/rustdoc-json/enums/discriminant/struct.rs [new file with mode: 0644]
src/test/rustdoc-json/enums/discriminant/tuple.rs [new file with mode: 0644]
src/test/rustdoc-json/enums/field_hidden.rs
src/test/rustdoc-json/enums/kind.rs
src/test/rustdoc-json/enums/struct_field_hidden.rs
src/test/rustdoc-json/enums/tuple_fields_hidden.rs
src/test/rustdoc-json/enums/variant_struct.rs
src/test/rustdoc-json/enums/variant_tuple_struct.rs
src/test/rustdoc-json/primitives/local_primitive.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/pub_use_doc_hidden.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105334.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105334.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-105737.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105737.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-105742.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105742.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-106213.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-106213.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-106226.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-106226.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-96287.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-96287.stderr [new file with mode: 0644]
src/test/rustdoc-ui/z-help.stdout
src/test/rustdoc/async-fn.rs
src/test/rustdoc/src-links.rs
src/test/rustdoc/src-links/fizz.rs [new file with mode: 0644]
src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
src/test/ui-fulldeps/deriving-global.rs
src/test/ui-fulldeps/deriving-hygiene.rs
src/test/ui-fulldeps/dropck_tarena_sound_drop.rs
src/test/ui-fulldeps/empty-struct-braces-derive.rs
src/test/ui-fulldeps/issue-14021.rs
src/test/ui-fulldeps/missing-rustc-driver-error.rs [new file with mode: 0644]
src/test/ui-fulldeps/missing-rustc-driver-error.stderr [new file with mode: 0644]
src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui-fulldeps/regions-mock-tcx.rs
src/test/ui-fulldeps/rustc_encodable_hygiene.rs
src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr
src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr
src/test/ui/alloc-error/alloc-error-handler-bad-signature-3.rs
src/test/ui/argument-suggestions/basic.rs
src/test/ui/argument-suggestions/display-is-suggestable.rs
src/test/ui/argument-suggestions/exotic-calls.rs
src/test/ui/argument-suggestions/extern-fn-arg-names.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/extern-fn-arg-names.stderr [new file with mode: 0644]
src/test/ui/argument-suggestions/extra_arguments.rs
src/test/ui/argument-suggestions/issue-100154.rs
src/test/ui/argument-suggestions/issue-100478.rs
src/test/ui/argument-suggestions/issue-101097.rs
src/test/ui/argument-suggestions/issue-96638.rs
src/test/ui/argument-suggestions/issue-97197.rs
src/test/ui/argument-suggestions/issue-97484.rs
src/test/ui/argument-suggestions/issue-98894.rs
src/test/ui/argument-suggestions/issue-98897.rs
src/test/ui/argument-suggestions/issue-99482.rs
src/test/ui/argument-suggestions/missing_arguments.rs
src/test/ui/argument-suggestions/mixed_cases.rs
src/test/ui/argument-suggestions/too-long.stderr
src/test/ui/array-slice-vec/slice-mut-2.stderr
src/test/ui/asm/aarch64/interpolated-idents.stderr
src/test/ui/asm/aarch64/type-check-2-2.rs
src/test/ui/asm/aarch64/type-check-2-2.stderr
src/test/ui/asm/x86_64/interpolated-idents.stderr
src/test/ui/asm/x86_64/type-check-5.rs
src/test/ui/asm/x86_64/type-check-5.stderr
src/test/ui/associated-consts/issue-105330.rs [new file with mode: 0644]
src/test/ui/associated-consts/issue-105330.stderr [new file with mode: 0644]
src/test/ui/associated-types/associated-type-projection-from-supertrait.stderr
src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
src/test/ui/associated-types/defaults-specialization.stderr
src/test/ui/associated-types/issue-25700-1.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-25700-2.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-25700.rs [new file with mode: 0644]
src/test/ui/associated-types/issue-25700.stderr [new file with mode: 0644]
src/test/ui/associated-types/issue-59324.rs
src/test/ui/associated-types/issue-59324.stderr
src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
src/test/ui/async-await/issue-105501.rs [new file with mode: 0644]
src/test/ui/async-await/issue-61452.stderr
src/test/ui/async-await/issues/issue-61187.stderr
src/test/ui/attributes/z-crate-attr.rs [new file with mode: 0644]
src/test/ui/augmented-assignments.rs
src/test/ui/augmented-assignments.stderr
src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
src/test/ui/borrowck/borrowck-access-permissions.stderr
src/test/ui/borrowck/borrowck-argument.stderr
src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr
src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr
src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr
src/test/ui/borrowck/borrowck-borrow-from-stack-variable.stderr
src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr
src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
src/test/ui/borrowck/borrowck-drop-from-guard.rs
src/test/ui/borrowck/borrowck-drop-from-guard.stderr
src/test/ui/borrowck/borrowck-issue-14498.stderr
src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr
src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr
src/test/ui/borrowck/borrowck-mutate-in-guard.rs
src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
src/test/ui/borrowck/borrowck-overloaded-call.stderr
src/test/ui/borrowck/borrowck-reborrow-from-mut.stderr
src/test/ui/borrowck/borrowck-ref-mut-of-imm.stderr
src/test/ui/borrowck/borrowck-unboxed-closures.stderr
src/test/ui/borrowck/immut-function-arguments.stderr
src/test/ui/borrowck/issue-31287-drop-in-guard.rs
src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
src/test/ui/borrowck/issue-85765.stderr
src/test/ui/borrowck/issue-93078.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-93078.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-93093.stderr
src/test/ui/borrowck/many-mutable-borrows.rs [new file with mode: 0644]
src/test/ui/borrowck/many-mutable-borrows.stderr [new file with mode: 0644]
src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
src/test/ui/borrowck/mutability-errors.rs
src/test/ui/borrowck/mutability-errors.stderr
src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed [new file with mode: 0644]
src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs
src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
src/test/ui/c-variadic/variadic-ffi-1.rs
src/test/ui/chalkify/arithmetic.rs
src/test/ui/chalkify/assert.rs
src/test/ui/chalkify/basic.rs
src/test/ui/chalkify/bugs/async.rs
src/test/ui/chalkify/builtin-copy-clone.rs
src/test/ui/chalkify/chalk_initial_program.rs
src/test/ui/chalkify/closure.rs
src/test/ui/chalkify/generic_impls.rs
src/test/ui/chalkify/impl_wf.rs
src/test/ui/chalkify/impl_wf_2.rs
src/test/ui/chalkify/inherent_impl.rs
src/test/ui/chalkify/inherent_impl_min.rs
src/test/ui/chalkify/lower_env1.rs
src/test/ui/chalkify/lower_env2.rs
src/test/ui/chalkify/lower_env3.rs
src/test/ui/chalkify/lower_impl.rs
src/test/ui/chalkify/lower_struct.rs
src/test/ui/chalkify/lower_trait.rs
src/test/ui/chalkify/lower_trait_higher_rank.rs
src/test/ui/chalkify/lower_trait_where_clause.rs
src/test/ui/chalkify/println.rs
src/test/ui/chalkify/projection.rs
src/test/ui/chalkify/recursive_where_clause_on_type.rs
src/test/ui/chalkify/recursive_where_clause_on_type.stderr
src/test/ui/chalkify/super_trait.rs
src/test/ui/chalkify/trait-objects.rs
src/test/ui/chalkify/trait_implied_bound.rs
src/test/ui/chalkify/type_implied_bound.rs
src/test/ui/chalkify/type_inference.rs
src/test/ui/chalkify/type_wf.rs
src/test/ui/check-cfg/well-known-values.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr
src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr
src/test/ui/closures/issue-80313-mutation-in-closure.stderr
src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr
src/test/ui/closures/issue-81700-mut-borrow.stderr
src/test/ui/closures/issue-82438-mut-without-upvar.stderr
src/test/ui/closures/issue-84044-drop-non-mut.stderr
src/test/ui/closures/supertrait-hint-cycle-2.rs [new file with mode: 0644]
src/test/ui/closures/supertrait-hint-cycle-3.rs [new file with mode: 0644]
src/test/ui/closures/supertrait-hint-cycle.rs [new file with mode: 0644]
src/test/ui/codegen/issue-82859-slice-miscompile.rs [new file with mode: 0644]
src/test/ui/codemap_tests/huge_multispan_highlight.stderr
src/test/ui/codemap_tests/tab_3.stderr
src/test/ui/coherence/coherence-default-trait-impl.stderr
src/test/ui/command/command-argv0-debug.rs [deleted file]
src/test/ui/command/issue-10626.rs [new file with mode: 0644]
src/test/ui/compare-method/bad-self-type.stderr
src/test/ui/compare-method/issue-90444.stderr
src/test/ui/compare-method/region-extra-2.stderr
src/test/ui/compare-method/region-extra.stderr
src/test/ui/compare-method/reordered-type-param.stderr
src/test/ui/const-generics/assoc_const_eq_diagnostic.rs [new file with mode: 0644]
src/test/ui/const-generics/assoc_const_eq_diagnostic.stderr [new file with mode: 0644]
src/test/ui/const-generics/ensure_is_evaluatable.rs [new file with mode: 0644]
src/test/ui/const-generics/ensure_is_evaluatable.stderr [new file with mode: 0644]
src/test/ui/const-generics/fn_with_two_const_inputs.rs [new file with mode: 0644]
src/test/ui/const-generics/fn_with_two_const_inputs.stderr [new file with mode: 0644]
src/test/ui/const-generics/fn_with_two_same_const_inputs.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-76595.rs
src/test/ui/const-generics/generic_const_exprs/issue-99647.rs [new file with mode: 0644]
src/test/ui/const-generics/incorrect-number-of-const-args.rs
src/test/ui/const-generics/issues/issue-105037.rs [new file with mode: 0644]
src/test/ui/const-generics/two_matching_preds.rs [new file with mode: 0644]
src/test/ui/const-generics/unify_with_nested_expr.rs [new file with mode: 0644]
src/test/ui/const-generics/unify_with_nested_expr.stderr [new file with mode: 0644]
src/test/ui/const-ptr/forbidden_slices.32bit.stderr [deleted file]
src/test/ui/const-ptr/forbidden_slices.64bit.stderr [deleted file]
src/test/ui/const-ptr/forbidden_slices.rs
src/test/ui/const-ptr/forbidden_slices.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/raw-bytes.32bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/raw-bytes.64bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/raw-bytes.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-enum.32bit.stderr
src/test/ui/consts/const-eval/ub-enum.64bit.stderr
src/test/ui/consts/const-eval/ub-enum.rs
src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-nonnull.rs
src/test/ui/consts/const-eval/ub-nonnull.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-ref-ptr.rs
src/test/ui/consts/const-eval/ub-ref-ptr.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-uninhabit.rs
src/test/ui/consts/const-eval/ub-uninhabit.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr [deleted file]
src/test/ui/consts/const-eval/ub-wide-ptr.rs
src/test/ui/consts/const-eval/ub-wide-ptr.stderr [new file with mode: 0644]
src/test/ui/consts/invalid-union.32bit.stderr
src/test/ui/consts/invalid-union.64bit.stderr
src/test/ui/consts/issue-103790.stderr
src/test/ui/consts/issue-83182.32bit.stderr [deleted file]
src/test/ui/consts/issue-83182.64bit.stderr [deleted file]
src/test/ui/consts/issue-83182.rs
src/test/ui/consts/issue-83182.stderr [new file with mode: 0644]
src/test/ui/consts/std/alloc.32bit.stderr
src/test/ui/consts/std/alloc.64bit.stderr
src/test/ui/consts/std/alloc.rs
src/test/ui/consts/validate_never_arrays.32bit.stderr [deleted file]
src/test/ui/consts/validate_never_arrays.64bit.stderr [deleted file]
src/test/ui/consts/validate_never_arrays.rs
src/test/ui/consts/validate_never_arrays.stderr [new file with mode: 0644]
src/test/ui/crate-loading/auxiliary/crateresolve1-1.rs
src/test/ui/crate-loading/auxiliary/crateresolve1-2.rs
src/test/ui/crate-loading/auxiliary/crateresolve1-3.rs
src/test/ui/crate-loading/crateresolve1.rs
src/test/ui/crate-loading/crateresolve1.stderr
src/test/ui/crate-loading/crateresolve2.rs
src/test/ui/crate-loading/crateresolve2.stderr
src/test/ui/did_you_mean/issue-35937.stderr
src/test/ui/did_you_mean/issue-38147-1.stderr
src/test/ui/did_you_mean/issue-38147-4.stderr
src/test/ui/did_you_mean/issue-39544.stderr
src/test/ui/did_you_mean/issue-40823.stderr
src/test/ui/drop/issue-2734.rs [new file with mode: 0644]
src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
src/test/ui/dropck/issue-34053.rs [new file with mode: 0644]
src/test/ui/dyn-star/align.normal.stderr
src/test/ui/dyn-star/align.over_aligned.stderr
src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
src/test/ui/dyn-star/feature-gate-dyn_star.stderr
src/test/ui/dyn-star/no-explicit-dyn-star-cast.stderr
src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
src/test/ui/dyn-star/return.stderr
src/test/ui/dyn-star/upcast.stderr
src/test/ui/enum-discriminant/issue-72554.rs [new file with mode: 0644]
src/test/ui/enum-discriminant/issue-72554.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0013.rs [new file with mode: 0644]
src/test/ui/error-codes/E0013.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0015.rs [new file with mode: 0644]
src/test/ui/error-codes/E0015.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0033-teach.rs
src/test/ui/error-codes/E0033-teach.stderr
src/test/ui/error-codes/E0033.rs
src/test/ui/error-codes/E0033.stderr
src/test/ui/error-codes/E0199.stderr
src/test/ui/error-codes/E0200.stderr
src/test/ui/error-codes/E0389.stderr
src/test/ui/error-codes/E0464.rs
src/test/ui/error-codes/E0464.stderr
src/test/ui/error-codes/E0519.rs [new file with mode: 0644]
src/test/ui/error-codes/E0519.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0596.stderr
src/test/ui/error-codes/E0637.stderr
src/test/ui/error-codes/E0711.rs [new file with mode: 0644]
src/test/ui/error-codes/E0711.stderr [new file with mode: 0644]
src/test/ui/error-codes/auxiliary/crateresolve1-1.rs
src/test/ui/error-codes/auxiliary/crateresolve1-2.rs
src/test/ui/error-codes/auxiliary/crateresolve1-3.rs
src/test/ui/expr/malformed_closure/ruby_style_closure.rs
src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
src/test/ui/extern/issue-13655.rs [new file with mode: 0644]
src/test/ui/feature-gates/stability-attribute-consistency.stderr
src/test/ui/fmt/auxiliary/format-string-proc-macro.rs
src/test/ui/fmt/ifmt-bad-arg.stderr
src/test/ui/fmt/issue-89173.rs
src/test/ui/fmt/issue-89173.stderr
src/test/ui/fmt/respanned-literal-issue-106191.rs [new file with mode: 0644]
src/test/ui/fmt/respanned-literal-issue-106191.stderr [new file with mode: 0644]
src/test/ui/fn/issue-3044.rs
src/test/ui/fn/issue-3044.stderr
src/test/ui/fn/issue-80179.rs
src/test/ui/fn/issue-80179.stderr
src/test/ui/fn/suggest-return-closure.rs [new file with mode: 0644]
src/test/ui/fn/suggest-return-closure.stderr [new file with mode: 0644]
src/test/ui/fn/suggest-return-future.rs [new file with mode: 0644]
src/test/ui/fn/suggest-return-future.stderr [new file with mode: 0644]
src/test/ui/function-pointer/unsized-ret.stderr
src/test/ui/functions-closures/fn-help-with-err.rs
src/test/ui/functions-closures/fn-help-with-err.stderr
src/test/ui/generator/issue-102645.rs
src/test/ui/generator/issue-102645.stderr
src/test/ui/generator/print/generator-print-verbose-1.stderr
src/test/ui/generic-associated-types/elided-in-expr-position.stderr
src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
src/test/ui/generic-associated-types/impl_bounds.rs
src/test/ui/generic-associated-types/impl_bounds.stderr
src/test/ui/generic-associated-types/issue-71176.stderr
src/test/ui/generic-associated-types/issue-76535.base.stderr
src/test/ui/generic-associated-types/issue-76535.extended.stderr
src/test/ui/generic-associated-types/issue-78671.base.stderr
src/test/ui/generic-associated-types/issue-78671.extended.stderr
src/test/ui/generic-associated-types/issue-79422.base.stderr
src/test/ui/generic-associated-types/issue-79422.extended.stderr
src/test/ui/generic-associated-types/issue-79636-1.stderr
src/test/ui/generic-associated-types/issue-79636-2.stderr
src/test/ui/generic-associated-types/issue-80433.stderr
src/test/ui/generic-associated-types/issue-81712-cyclic-traits.stderr
src/test/ui/generic-associated-types/issue-81862.stderr
src/test/ui/generic-associated-types/issue-90014.stderr
src/test/ui/generic-associated-types/issue-91139.rs
src/test/ui/generic-associated-types/issue-91139.stderr
src/test/ui/generic-associated-types/issue-91883.stderr
src/test/ui/generic-associated-types/issue-92033.stderr
src/test/ui/generic-associated-types/mismatched-where-clause-regions.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/mismatched-where-clause-regions.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
src/test/ui/generic-associated-types/missing_lifetime_args.stderr
src/test/ui/generics/generic-type-less-params-with-defaults.stderr
src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
src/test/ui/generics/wrong-number-of-args.stderr
src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/issue-58451.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed [new file with mode: 0644]
src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs [new file with mode: 0644]
src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr [new file with mode: 0644]
src/test/ui/illegal-sized-bound/mutability-mismatch.rs
src/test/ui/illegal-sized-bound/mutability-mismatch.stderr
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs
src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr
src/test/ui/impl-trait/in-trait/box-coerce-span-in-default.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/method-signature-matches.stderr
src/test/ui/impl-trait/in-trait/signature-mismatch.stderr
src/test/ui/impl-trait/in-trait/specialization-broken.stderr
src/test/ui/impl-trait/issue-72911.rs
src/test/ui/impl-trait/issue-72911.stderr
src/test/ui/impl-trait/issues/issue-92305.stderr
src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
src/test/ui/impl-trait/static-return-lifetime-infered.rs
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
src/test/ui/impl-trait/trait_type.stderr
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
src/test/ui/issues/issue-105330.rs [deleted file]
src/test/ui/issues/issue-105330.stderr [deleted file]
src/test/ui/issues/issue-10536.rs [deleted file]
src/test/ui/issues/issue-10536.stderr [deleted file]
src/test/ui/issues/issue-10626.rs [deleted file]
src/test/ui/issues/issue-11374.stderr
src/test/ui/issues/issue-13033.rs
src/test/ui/issues/issue-13033.stderr
src/test/ui/issues/issue-13497-2.stderr
src/test/ui/issues/issue-13655.rs [deleted file]
src/test/ui/issues/issue-14092.stderr
src/test/ui/issues/issue-15094.rs
src/test/ui/issues/issue-15094.stderr
src/test/ui/issues/issue-18611.stderr
src/test/ui/issues/issue-18937-1.rs [deleted file]
src/test/ui/issues/issue-18937.rs [deleted file]
src/test/ui/issues/issue-18937.stderr [deleted file]
src/test/ui/issues/issue-20225.stderr
src/test/ui/issues/issue-20831-debruijn.stderr
src/test/ui/issues/issue-21332.stderr
src/test/ui/issues/issue-21763.stderr
src/test/ui/issues/issue-23024.stderr
src/test/ui/issues/issue-25386.rs
src/test/ui/issues/issue-25386.stderr
src/test/ui/issues/issue-25439.stderr
src/test/ui/issues/issue-25700-1.rs [deleted file]
src/test/ui/issues/issue-25700-2.rs [deleted file]
src/test/ui/issues/issue-25700.rs [deleted file]
src/test/ui/issues/issue-25700.stderr [deleted file]
src/test/ui/issues/issue-26094.rs
src/test/ui/issues/issue-2734.rs [deleted file]
src/test/ui/issues/issue-29723.rs
src/test/ui/issues/issue-29723.stderr
src/test/ui/issues/issue-31173.rs [deleted file]
src/test/ui/issues/issue-31173.stderr [deleted file]
src/test/ui/issues/issue-34053.rs [deleted file]
src/test/ui/issues/issue-35570.stderr
src/test/ui/issues/issue-36400.stderr
src/test/ui/issues/issue-37884.stderr
src/test/ui/issues/issue-48364.stderr
src/test/ui/issues/issue-4935.rs
src/test/ui/issues/issue-51515.stderr
src/test/ui/issues/issue-54189.rs [deleted file]
src/test/ui/issues/issue-54189.stderr [deleted file]
src/test/ui/issues/issue-61623.stderr
src/test/ui/issues/issue-67535.rs [new file with mode: 0644]
src/test/ui/issues/issue-67535.stderr [new file with mode: 0644]
src/test/ui/issues/issue-72554.rs [deleted file]
src/test/ui/issues/issue-72554.stderr [deleted file]
src/test/ui/issues/issue-82859-slice-miscompile.rs [deleted file]
src/test/ui/issues/issue-86756.stderr
src/test/ui/issues/issue-99875.rs [deleted file]
src/test/ui/issues/issue-99875.stderr [deleted file]
src/test/ui/layout/thin-meta-implies-thin-ptr.rs [new file with mode: 0644]
src/test/ui/lexer/error-stage.stderr
src/test/ui/lexer/lex-bad-char-literals-6.rs
src/test/ui/lexer/lex-bad-char-literals-6.stderr
src/test/ui/lexer/lex-bad-numeric-literals.rs
src/test/ui/lexer/lex-bad-numeric-literals.stderr
src/test/ui/lifetimes/issue-105227.fixed [new file with mode: 0644]
src/test/ui/lifetimes/issue-105227.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-105227.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-26638.rs
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
src/test/ui/lifetimes/missing-lifetime-in-alias.stderr
src/test/ui/lint/unused/must-use-box-from-raw.stderr
src/test/ui/lint/unused_braces_macro.rs [new file with mode: 0644]
src/test/ui/macros/best-failure.rs [new file with mode: 0644]
src/test/ui/macros/best-failure.stderr [new file with mode: 0644]
src/test/ui/macros/format-foreign.stderr
src/test/ui/macros/format-unused-lables.stderr
src/test/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr
src/test/ui/macros/issue-10536.rs [new file with mode: 0644]
src/test/ui/macros/issue-10536.stderr [new file with mode: 0644]
src/test/ui/macros/issue-92267.stderr
src/test/ui/macros/span-covering-argument-1.stderr
src/test/ui/macros/stringify.rs
src/test/ui/match/single-line.rs [new file with mode: 0644]
src/test/ui/match/single-line.stderr [new file with mode: 0644]
src/test/ui/methods/issues/issue-105732.rs
src/test/ui/methods/issues/issue-105732.stderr
src/test/ui/methods/issues/issue-61525.stderr
src/test/ui/methods/issues/issue-90315.rs
src/test/ui/methods/issues/issue-90315.stderr
src/test/ui/methods/method-call-err-msg.rs
src/test/ui/methods/method-call-err-msg.stderr
src/test/ui/mismatched_types/E0053.stderr
src/test/ui/mismatched_types/issue-106182.fixed [new file with mode: 0644]
src/test/ui/mismatched_types/issue-106182.rs [new file with mode: 0644]
src/test/ui/mismatched_types/issue-106182.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
src/test/ui/mismatched_types/overloaded-calls-bad.rs
src/test/ui/mismatched_types/ref-pat-suggestions.stderr
src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
src/test/ui/moves/move-fn-self-receiver.stderr
src/test/ui/moves/moves-based-on-type-access-to-field.stderr
src/test/ui/moves/moves-based-on-type-exprs.stderr
src/test/ui/moves/pin-mut-reborrow.fixed [new file with mode: 0644]
src/test/ui/moves/pin-mut-reborrow.rs [new file with mode: 0644]
src/test/ui/moves/pin-mut-reborrow.stderr [new file with mode: 0644]
src/test/ui/moves/suggest-clone.fixed [new file with mode: 0644]
src/test/ui/moves/suggest-clone.rs [new file with mode: 0644]
src/test/ui/moves/suggest-clone.stderr [new file with mode: 0644]
src/test/ui/mut/mut-suggestion.rs
src/test/ui/mut/mut-suggestion.stderr
src/test/ui/mut/mutable-class-fields-2.stderr
src/test/ui/mut/mutable-class-fields.stderr
src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs
src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr
src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
src/test/ui/nll/issue-27282-mutation-in-guard.rs
src/test/ui/nll/issue-27282-mutation-in-guard.stderr
src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
src/test/ui/nll/issue-47388.stderr
src/test/ui/nll/issue-51191.stderr
src/test/ui/nll/issue-51244.stderr
src/test/ui/nll/issue-54189.rs [new file with mode: 0644]
src/test/ui/nll/issue-54189.stderr [new file with mode: 0644]
src/test/ui/nll/issue-57989.stderr
src/test/ui/nll/match-cfg-fake-edges.rs
src/test/ui/nll/match-cfg-fake-edges.stderr
src/test/ui/nll/match-guards-always-borrow.rs
src/test/ui/nll/match-guards-always-borrow.stderr
src/test/ui/nll/match-guards-partially-borrow.rs
src/test/ui/nll/match-guards-partially-borrow.stderr
src/test/ui/nll/normalization-bounds-error.stderr
src/test/ui/nll/ty-outlives/wf-unreachable.stderr
src/test/ui/nll/user-annotations/ascribed-type-wf.rs
src/test/ui/nll/user-annotations/ascribed-type-wf.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/closure-sig.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-2.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-2.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-default.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-default.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-infer.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-infer.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-self.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization-self.stderr [new file with mode: 0644]
src/test/ui/nll/user-annotations/normalization.rs
src/test/ui/nll/user-annotations/normalization.stderr
src/test/ui/not-enough-arguments.rs
src/test/ui/object-safety/issue-106247.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/enum-2.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/enum-2.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/enum.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/enum.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/fn-arg.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/fn-arg.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/item-with-attr.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/item-with-attr.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/item.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/item.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/statement.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/statement.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/struct-expr.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/struct-expr.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/struct.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/struct.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/trait-item.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/trait-item.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/tuple-struct.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/tuple-struct.stderr [new file with mode: 0644]
src/test/ui/parser/diff-markers/use-statement.rs [new file with mode: 0644]
src/test/ui/parser/diff-markers/use-statement.stderr [new file with mode: 0644]
src/test/ui/parser/int-literal-too-large-span.stderr
src/test/ui/parser/intersection-patterns-1.fixed [new file with mode: 0644]
src/test/ui/parser/intersection-patterns-1.rs [new file with mode: 0644]
src/test/ui/parser/intersection-patterns-1.stderr [new file with mode: 0644]
src/test/ui/parser/intersection-patterns-2.rs [new file with mode: 0644]
src/test/ui/parser/intersection-patterns-2.stderr [new file with mode: 0644]
src/test/ui/parser/intersection-patterns.rs [deleted file]
src/test/ui/parser/intersection-patterns.stderr [deleted file]
src/test/ui/parser/issues/issue-5544-a.stderr
src/test/ui/parser/issues/issue-5544-b.stderr
src/test/ui/parser/kw-in-trait-bounds.rs
src/test/ui/parser/kw-in-trait-bounds.stderr
src/test/ui/parser/nested-bad-turbofish.rs [new file with mode: 0644]
src/test/ui/parser/nested-bad-turbofish.stderr [new file with mode: 0644]
src/test/ui/parser/recover-fn-trait-from-fn-kw.rs [new file with mode: 0644]
src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
src/test/ui/privacy/private-field-ty-err.rs [new file with mode: 0644]
src/test/ui/privacy/private-field-ty-err.stderr [new file with mode: 0644]
src/test/ui/process/process-panic-after-fork.rs
src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.stderr
src/test/ui/regions/regions-free-region-ordering-caller.stderr
src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
src/test/ui/regions/regions-outlives-projection-container-hrtb.stderr
src/test/ui/regions/regions-outlives-projection-container-wc.stderr
src/test/ui/regions/regions-outlives-projection-container.stderr
src/test/ui/repr/transparent-enum-too-many-variants.rs [new file with mode: 0644]
src/test/ui/repr/transparent-enum-too-many-variants.stderr [new file with mode: 0644]
src/test/ui/resolve/resolve-primitive-fallback.rs
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
src/test/ui/rfc-2091-track-caller/call-chain.rs
src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs [new file with mode: 0644]
src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed [new file with mode: 0644]
src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs
src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr
src/test/ui/span/borrowck-fn-in-const-b.stderr
src/test/ui/span/borrowck-object-mutability.stderr
src/test/ui/span/issue-34264.rs
src/test/ui/span/missing-unit-argument.rs
src/test/ui/span/missing-unit-argument.stderr
src/test/ui/span/mut-arg-hint.stderr
src/test/ui/specialization/min_specialization/issue-79224.rs
src/test/ui/specialization/min_specialization/issue-79224.stderr
src/test/ui/stability-attribute/stability-attribute-sanity.stderr
src/test/ui/stats/hir-stats.stderr
src/test/ui/suggestions/args-instead-of-tuple-errors.rs
src/test/ui/suggestions/args-instead-of-tuple.fixed
src/test/ui/suggestions/args-instead-of-tuple.rs
src/test/ui/suggestions/args-instead-of-tuple.stderr
src/test/ui/suggestions/bad-hex-float-lit.rs [new file with mode: 0644]
src/test/ui/suggestions/bad-hex-float-lit.stderr [new file with mode: 0644]
src/test/ui/suggestions/imm-ref-trait-object.rs
src/test/ui/suggestions/imm-ref-trait-object.stderr
src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs
src/test/ui/suggestions/issue-104287.rs
src/test/ui/suggestions/issue-104287.stderr
src/test/ui/suggestions/issue-105645.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-105645.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-106443-sugg-clone-for-arg.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-106443-sugg-clone-for-arg.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-106443-sugg-clone-for-bound.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-68049-2.stderr
src/test/ui/suggestions/issue-99240-2.stderr
src/test/ui/suggestions/method-access-to-range-literal-typo.rs [new file with mode: 0644]
src/test/ui/suggestions/method-access-to-range-literal-typo.stderr [new file with mode: 0644]
src/test/ui/suggestions/missing-type-param-used-in-param.fixed
src/test/ui/suggestions/missing-type-param-used-in-param.rs
src/test/ui/suggestions/option-content-move.stderr
src/test/ui/suggestions/shadowed-lplace-method-2.rs [new file with mode: 0644]
src/test/ui/suggestions/shadowed-lplace-method-2.stderr [new file with mode: 0644]
src/test/ui/suggestions/shadowed-lplace-method.fixed [new file with mode: 0644]
src/test/ui/suggestions/shadowed-lplace-method.rs [new file with mode: 0644]
src/test/ui/suggestions/shadowed-lplace-method.stderr [new file with mode: 0644]
src/test/ui/suggestions/sugg-else-for-closure.stderr
src/test/ui/suggestions/suggest-ref-mut.stderr
src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr
src/test/ui/suggestions/unnamable-types.stderr
src/test/ui/tag-type-args.stderr
src/test/ui/thir-tree.stdout
src/test/ui/traits/impl-method-mismatch.rs
src/test/ui/traits/impl-method-mismatch.stderr
src/test/ui/traits/issue-35869.stderr
src/test/ui/traits/issue-52893.stderr
src/test/ui/traits/issue-91594.stderr
src/test/ui/traits/issue-99875.rs [new file with mode: 0644]
src/test/ui/traits/issue-99875.stderr [new file with mode: 0644]
src/test/ui/traits/matching-lifetimes.stderr
src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr
src/test/ui/traits/param-without-lifetime-constraint.stderr
src/test/ui/traits/safety-trait-impl-cc.stderr
src/test/ui/traits/safety-trait-impl.stderr
src/test/ui/traits/self-without-lifetime-constraint.stderr
src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr
src/test/ui/tuple/add-tuple-within-arguments.rs
src/test/ui/tuple/add-tuple-within-arguments.stderr
src/test/ui/tuple/wrong_argument_ice-2.rs
src/test/ui/tuple/wrong_argument_ice-2.stderr
src/test/ui/tuple/wrong_argument_ice-3.rs
src/test/ui/tuple/wrong_argument_ice-3.stderr
src/test/ui/tuple/wrong_argument_ice-4.rs
src/test/ui/tuple/wrong_argument_ice.rs
src/test/ui/tuple/wrong_argument_ice.stderr
src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs [new file with mode: 0644]
src/test/ui/type/ascription/issue-34255-1.stderr
src/test/ui/type/binding-assigned-block-without-tail-expression.rs [new file with mode: 0644]
src/test/ui/type/binding-assigned-block-without-tail-expression.stderr [new file with mode: 0644]
src/test/ui/type/closure-with-wrong-borrows.rs [new file with mode: 0644]
src/test/ui/type/closure-with-wrong-borrows.stderr [new file with mode: 0644]
src/test/ui/type/issue-102598.rs [new file with mode: 0644]
src/test/ui/type/issue-102598.stderr [new file with mode: 0644]
src/test/ui/type/issue-58355.rs [new file with mode: 0644]
src/test/ui/type/issue-58355.stderr [new file with mode: 0644]
src/test/ui/type/type-ascription-instead-of-initializer.rs
src/test/ui/type/type-check/assignment-in-if.stderr
src/test/ui/type/type-check/point-at-inference-2.rs [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference-2.stderr [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference-3.fixed [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference-3.rs [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference-3.stderr [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference.fixed [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference.rs [new file with mode: 0644]
src/test/ui/type/type-check/point-at-inference.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-105946.rs [new file with mode: 0644]
src/test/ui/typeck/issue-105946.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-18937-1.rs [new file with mode: 0644]
src/test/ui/typeck/issue-18937.rs [new file with mode: 0644]
src/test/ui/typeck/issue-18937.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-31173.rs [new file with mode: 0644]
src/test/ui/typeck/issue-31173.stderr [new file with mode: 0644]
src/test/ui/typeck/nonexistent-field-not-ambiguous.rs [new file with mode: 0644]
src/test/ui/typeck/nonexistent-field-not-ambiguous.stderr [new file with mode: 0644]
src/test/ui/typeck/quiet-type-err-let-binding.rs [new file with mode: 0644]
src/test/ui/typeck/quiet-type-err-let-binding.stderr [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.fixed
src/test/ui/typeck/remove-extra-argument.rs
src/test/ui/typeck/typeck_type_placeholder_item.rs
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/ufcs/ufcs-partially-resolved.stderr
src/test/ui/ufcs/ufcs-qpath-missing-params.stderr
src/test/ui/unboxed-closures/unboxed-closure-no-cyclic-sig.stderr
src/test/ui/unboxed-closures/unboxed-closure-region.rs
src/test/ui/unboxed-closures/unboxed-closure-region.stderr
src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr
src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr
src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr
src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr
src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr
src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr
src/test/ui/unsafe/auxiliary/issue-106126.rs [new file with mode: 0644]
src/test/ui/unsafe/issue-106126-good-path-bug.rs [new file with mode: 0644]
src/test/ui/unsafe/unsafe-trait-impl.rs
src/test/ui/unsafe/unsafe-trait-impl.stderr
src/test/ui/unsized-locals/suggest-borrow.rs [new file with mode: 0644]
src/test/ui/unsized-locals/suggest-borrow.stderr [new file with mode: 0644]
src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr
src/test/ui/unsized/unsized6.stderr
src/test/ui/variance/variance-associated-consts.stderr
src/test/ui/variance/variance-associated-types.stderr
src/test/ui/variance/variance-object-types.stderr
src/test/ui/variance/variance-regions-direct.stderr
src/test/ui/variance/variance-regions-indirect.stderr
src/test/ui/variance/variance-trait-bounds.stderr
src/test/ui/variance/variance-trait-object-bound.stderr
src/test/ui/variance/variance-types-bounds.stderr
src/test/ui/variance/variance-types.stderr
src/test/ui/wf/issue-103573.stderr
src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
src/test/ui/writing-to-immutable-vec.stderr
src/test/ui/wrong-mul-method-signature.stderr
src/test/ui/z-crate-attr.rs [deleted file]
src/tools/build-manifest/src/main.rs
src/tools/build_helper/Cargo.toml [new file with mode: 0644]
src/tools/build_helper/src/ci.rs [new file with mode: 0644]
src/tools/build_helper/src/git.rs [new file with mode: 0644]
src/tools/build_helper/src/lib.rs [new file with mode: 0644]
src/tools/bump-stage0/src/main.rs
src/tools/cargo
src/tools/clippy/CHANGELOG.md
src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
src/tools/clippy/clippy_lints/src/declared_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/fn_null_check.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/functions/mod.rs
src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
src/tools/clippy/clippy_lints/src/large_const_arrays.rs
src/tools/clippy/clippy_lints/src/large_enum_variant.rs
src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
src/tools/clippy/clippy_lints/src/manual_async_fn.rs
src/tools/clippy/clippy_lints/src/manual_clamp.rs
src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
src/tools/clippy/clippy_lints/src/manual_strip.rs
src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
src/tools/clippy/clippy_lints/src/mut_mut.rs
src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
src/tools/clippy/clippy_lints/src/needless_late_init.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/non_copy_const.rs
src/tools/clippy/clippy_lints/src/octal_escapes.rs
src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/redundant_clone.rs
src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
src/tools/clippy/clippy_lints/src/ref_option_ref.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/same_name_method.rs
src/tools/clippy/clippy_lints/src/size_of_ref.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/swap.rs
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
src/tools/clippy/clippy_lints/src/types/mod.rs
src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
src/tools/clippy/clippy_lints/src/types/type_complexity.rs
src/tools/clippy/clippy_lints/src/types/utils.rs
src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
src/tools/clippy/clippy_lints/src/useless_conversion.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_utils/src/ast_utils.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/diagnostics.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs [deleted file]
src/tools/clippy/clippy_utils/src/mir/mod.rs
src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/ui/async_yields_async.stderr
src/tools/clippy/tests/ui/crashes/ice-10044.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-10044.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_powi.fixed
src/tools/clippy/tests/ui/floating_point_powi.rs
src/tools/clippy/tests/ui/floating_point_powi.stderr
src/tools/clippy/tests/ui/fn_null_check.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/fn_null_check.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_filter.fixed
src/tools/clippy/tests/ui/manual_filter.rs
src/tools/clippy/tests/ui/manual_retain.fixed
src/tools/clippy/tests/ui/manual_retain.rs
src/tools/clippy/tests/ui/match_single_binding.fixed
src/tools/clippy/tests/ui/match_single_binding.rs
src/tools/clippy/tests/ui/match_single_binding.stderr
src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
src/tools/clippy/tests/ui/needless_borrow.fixed
src/tools/clippy/tests/ui/needless_borrow.rs
src/tools/clippy/tests/ui/needless_borrow.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/permissions_set_readonly_false.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/redundant_clone.fixed
src/tools/clippy/tests/ui/redundant_clone.rs
src/tools/clippy/tests/ui/redundant_clone.stderr
src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr
src/tools/clippy/tests/ui/size_of_ref.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/size_of_ref.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/transmute_null_to_fn.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/transmute_null_to_fn.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/useless_conversion.fixed
src/tools/clippy/tests/ui/useless_conversion.rs
src/tools/clippy/tests/ui/useless_conversion.stderr
src/tools/clippy/tests/ui/wildcard_imports.fixed
src/tools/clippy/tests/ui/wildcard_imports.rs
src/tools/clippy/tests/ui/wildcard_imports.stderr
src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/wildcard_imports_2021.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/wildcard_imports_2021.stderr [new file with mode: 0644]
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/error_index_generator/book_config.toml
src/tools/error_index_generator/main.rs
src/tools/error_index_generator/redirect.js
src/tools/jsondoclint/Cargo.toml
src/tools/jsondoclint/src/json_find.rs
src/tools/jsondoclint/src/main.rs
src/tools/jsondoclint/src/validator.rs
src/tools/jsondoclint/src/validator/tests.rs
src/tools/miri/Cargo.lock
src/tools/miri/cargo-miri/Cargo.lock
src/tools/miri/cargo-miri/Cargo.toml
src/tools/miri/cargo-miri/src/phases.rs
src/tools/miri/cargo-miri/src/setup.rs
src/tools/miri/ci.sh
src/tools/miri/src/lib.rs
src/tools/miri/src/shims/foreign_items.rs
src/tools/miri/src/shims/tls.rs
src/tools/miri/src/shims/unix/foreign_items.rs
src/tools/miri/test-cargo-miri/Cargo.lock
src/tools/miri/test_dependencies/Cargo.lock
src/tools/miri/test_dependencies/Cargo.toml
src/tools/miri/tests/avr.json [new file with mode: 0644]
src/tools/miri/tests/extern-so/fail/function_not_in_so.rs
src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr
src/tools/miri/tests/fail/alloc/no_global_allocator.rs
src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
src/tools/miri/tests/fail/unsupported_foreign_function.rs
src/tools/miri/tests/fail/unsupported_foreign_function.stderr
src/tools/miri/tests/fail/unsupported_incomplete_function.rs [new file with mode: 0644]
src/tools/miri/tests/fail/unsupported_incomplete_function.stderr [new file with mode: 0644]
src/tools/miri/tests/fail/unsupported_signal.rs [deleted file]
src/tools/miri/tests/fail/unsupported_signal.stderr [deleted file]
src/tools/miri/tests/panic/unsupported_foreign_function.rs
src/tools/miri/tests/panic/unsupported_foreign_function.stderr
src/tools/rust-installer
src/tools/rustc-workspace-hack/Cargo.toml
src/tools/rustdoc-gui/tester.js
src/tools/rustfmt/src/lib.rs
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/tests/target/issue_4110.rs
src/tools/tidy/Cargo.toml
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes.rs [new file with mode: 0644]
src/tools/tidy/src/error_codes_check.rs [deleted file]
src/tools/tidy/src/errors.rs [deleted file]
src/tools/tidy/src/features/version/tests.rs
src/tools/tidy/src/lib.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/style.rs
src/tools/tidy/src/ui_tests.rs
src/tools/tidy/src/x_version.rs [new file with mode: 0644]
src/tools/x/src/main.rs
triagebot.toml
x.ps1

index 97148641670f448e9751683d2348d6c8e7d12e04..da47b08c7df55bc54fa99408563defa00803d51e 100644 (file)
@@ -30,7 +30,7 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
 dependencies = [
- "getrandom 0.2.8",
+ "getrandom",
  "once_cell",
  "version_check",
 ]
@@ -50,7 +50,7 @@ version = "0.0.0"
 dependencies = [
  "compiler_builtins",
  "core",
- "rand 0.7.3",
+ "rand",
  "rand_xorshift",
 ]
 
@@ -197,6 +197,18 @@ dependencies = [
  "rustc-demangle",
 ]
 
+[[package]]
+name = "base16ct"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
+
+[[package]]
+name = "base64ct"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -259,6 +271,10 @@ dependencies = [
  "toml",
 ]
 
+[[package]]
+name = "build_helper"
+version = "0.1.0"
+
 [[package]]
 name = "bump-stage0"
 version = "0.1.0"
@@ -271,6 +287,12 @@ dependencies = [
  "toml",
 ]
 
+[[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
 [[package]]
 name = "bytecount"
 version = "0.6.2"
@@ -341,6 +363,7 @@ dependencies = [
  "opener",
  "openssl",
  "os_info",
+ "pasetors",
  "pathdiff",
  "percent-encoding",
  "pretty_env_logger",
@@ -358,6 +381,7 @@ dependencies = [
  "tar",
  "tempfile",
  "termcolor",
+ "time 0.3.17",
  "toml_edit",
  "unicode-width",
  "unicode-xid",
@@ -443,10 +467,13 @@ dependencies = [
  "glob",
  "itertools",
  "lazy_static",
+ "pasetors",
+ "serde",
  "serde_json",
  "snapbox",
  "tar",
  "termcolor",
+ "time 0.3.17",
  "toml_edit",
  "url",
  "winapi",
@@ -585,7 +612,7 @@ dependencies = [
  "num-integer",
  "num-traits",
  "serde",
- "time",
+ "time 0.1.43",
  "winapi",
 ]
 
@@ -597,7 +624,7 @@ checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
 dependencies = [
  "atty",
  "bitflags",
- "clap_derive",
+ "clap_derive 3.2.18",
  "clap_lex 0.2.2",
  "indexmap",
  "once_cell",
@@ -614,7 +641,9 @@ checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
 dependencies = [
  "atty",
  "bitflags",
+ "clap_derive 4.0.13",
  "clap_lex 0.3.0",
+ "once_cell",
  "strsim",
  "termcolor",
 ]
@@ -641,6 +670,19 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "clap_derive"
+version = "4.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "clap_lex"
 version = "0.2.2"
@@ -884,6 +926,12 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317"
 
+[[package]]
+name = "const-oid"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
+
 [[package]]
 name = "content_inspector"
 version = "0.2.4"
@@ -903,7 +951,7 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
 name = "core"
 version = "0.0.0"
 dependencies = [
- "rand 0.7.3",
+ "rand",
  "rand_xorshift",
 ]
 
@@ -938,7 +986,7 @@ dependencies = [
 
 [[package]]
 name = "crates-io"
-version = "0.35.0"
+version = "0.35.1"
 dependencies = [
  "anyhow",
  "curl",
@@ -1000,13 +1048,26 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "crypto-bigint"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "crypto-common"
-version = "0.1.2"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
+ "typenum",
 ]
 
 [[package]]
@@ -1031,6 +1092,12 @@ dependencies = [
  "quote",
 ]
 
+[[package]]
+name = "ct-codecs"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
+
 [[package]]
 name = "ctor"
 version = "0.1.26"
@@ -1087,6 +1154,17 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "der"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
+dependencies = [
+ "const-oid",
+ "pem-rfc7468",
+ "zeroize",
+]
+
 [[package]]
 name = "derive-new"
 version = "0.5.8"
@@ -1125,12 +1203,13 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 
 [[package]]
 name = "digest"
-version = "0.10.2"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
  "block-buffer",
  "crypto-common",
+ "subtle",
 ]
 
 [[package]]
@@ -1217,6 +1296,27 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
 
+[[package]]
+name = "ecdsa"
+version = "0.14.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
+dependencies = [
+ "der",
+ "elliptic-curve",
+ "rfc6979",
+ "signature",
+]
+
+[[package]]
+name = "ed25519-compact"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c"
+dependencies = [
+ "getrandom",
+]
+
 [[package]]
 name = "either"
 version = "1.6.0"
@@ -1235,6 +1335,28 @@ dependencies = [
  "serde_json",
 ]
 
+[[package]]
+name = "elliptic-curve"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
+dependencies = [
+ "base16ct",
+ "crypto-bigint",
+ "der",
+ "digest",
+ "ff",
+ "generic-array",
+ "group",
+ "hkdf",
+ "pem-rfc7468",
+ "pkcs8",
+ "rand_core",
+ "sec1",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "ena"
 version = "0.14.0"
@@ -1354,6 +1476,22 @@ dependencies = [
  "instant",
 ]
 
+[[package]]
+name = "ff"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
+dependencies = [
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "fiat-crypto"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90"
+
 [[package]]
 name = "filetime"
 version = "0.2.14"
@@ -1611,17 +1749,6 @@ dependencies = [
  "unicode-width",
 ]
 
-[[package]]
-name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
-]
-
 [[package]]
 name = "getrandom"
 version = "0.2.8"
@@ -1629,8 +1756,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
+ "js-sys",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -1693,6 +1822,17 @@ dependencies = [
  "regex",
 ]
 
+[[package]]
+name = "group"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
 [[package]]
 name = "gsgdt"
 version = "0.1.2"
@@ -1782,6 +1922,24 @@ version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
 
+[[package]]
+name = "hkdf"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
+dependencies = [
+ "hmac",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
 [[package]]
 name = "home"
 version = "0.5.3"
@@ -1946,7 +2104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe"
 dependencies = [
  "bitmaps",
- "rand_core 0.6.2",
+ "rand_core",
  "rand_xoshiro",
  "sized-chunks",
  "typenum",
@@ -2079,6 +2237,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "jsondocck"
 version = "0.1.0"
@@ -2097,8 +2264,10 @@ name = "jsondoclint"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "clap 4.0.15",
  "fs-err",
  "rustdoc-json-types",
+ "serde",
  "serde_json",
 ]
 
@@ -2480,14 +2649,14 @@ version = "0.1.0"
 dependencies = [
  "colored",
  "env_logger 0.9.0",
- "getrandom 0.2.8",
+ "getrandom",
  "lazy_static",
  "libc",
  "libffi",
  "libloading",
  "log",
  "measureme",
- "rand 0.8.5",
+ "rand",
  "regex",
  "rustc-workspace-hack",
  "rustc_version",
@@ -2647,6 +2816,17 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "orion"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2baf7fd2e326e3895c681176788dd227fcd8369350e53c570592d8563fecbb6"
+dependencies = [
+ "fiat-crypto",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "os_info"
 version = "3.5.0"
@@ -2675,9 +2855,20 @@ dependencies = [
 
 [[package]]
 name = "owo-colors"
-version = "3.4.0"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
+
+[[package]]
+name = "p384"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b"
+checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa"
+dependencies = [
+ "ecdsa",
+ "elliptic-curve",
+ "sha2",
+]
 
 [[package]]
 name = "packed_simd_2"
@@ -2760,12 +2951,42 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "pasetors"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed20c4c21d893414f42e0cbfebe8a8036b5ae9b0264611fb6504e395eda6ceec"
+dependencies = [
+ "ct-codecs",
+ "ed25519-compact",
+ "getrandom",
+ "orion",
+ "p384",
+ "rand_core",
+ "regex",
+ "serde",
+ "serde_json",
+ "sha2",
+ "subtle",
+ "time 0.3.17",
+ "zeroize",
+]
+
 [[package]]
 name = "pathdiff"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
 
+[[package]]
+name = "pem-rfc7468"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
+dependencies = [
+ "base64ct",
+]
+
 [[package]]
 name = "percent-encoding"
 version = "2.1.0"
@@ -2861,7 +3082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
 dependencies = [
  "phf_shared",
- "rand 0.8.5",
+ "rand",
 ]
 
 [[package]]
@@ -2885,6 +3106,16 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
+[[package]]
+name = "pkcs8"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
+dependencies = [
+ "der",
+ "spki",
+]
+
 [[package]]
 name = "pkg-config"
 version = "0.3.25"
@@ -3056,19 +3287,6 @@ dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
-]
-
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -3076,18 +3294,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
- "rand_chacha 0.3.0",
- "rand_core 0.6.2",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
+ "rand_chacha",
+ "rand_core",
 ]
 
 [[package]]
@@ -3097,43 +3305,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.2",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
-dependencies = [
- "getrandom 0.2.8",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "rand_core 0.5.1",
+ "getrandom",
 ]
 
 [[package]]
 name = "rand_xorshift"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
+checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
 dependencies = [
- "rand_core 0.5.1",
+ "rand_core",
 ]
 
 [[package]]
@@ -3142,7 +3332,7 @@ version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
 dependencies = [
- "rand_core 0.6.2",
+ "rand_core",
 ]
 
 [[package]]
@@ -3184,7 +3374,7 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
 dependencies = [
- "getrandom 0.2.8",
+ "getrandom",
  "redox_syscall",
 ]
 
@@ -3248,6 +3438,17 @@ dependencies = [
  "walkdir",
 ]
 
+[[package]]
+name = "rfc6979"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
+dependencies = [
+ "crypto-bigint",
+ "hmac",
+ "zeroize",
+]
+
 [[package]]
 name = "rls"
 version = "2.0.0"
@@ -3295,9 +3496,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20c4b4625eeb148cccf82d5e9b90ad7fab3b11a0204cf75cc7fa04981a0fdffd"
+checksum = "d65b1271cdac365b71b59570ea35d945dea2dd2cc47eba3d33b4bd1e0190ac6d"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -3387,9 +3588,10 @@ version = "1.0.0"
 dependencies = [
  "bstr 0.2.17",
  "clap 3.2.20",
+ "getrandom",
  "libc",
  "libz-sys",
- "rand 0.8.5",
+ "rand",
  "regex",
  "serde_json",
  "syn",
@@ -3402,7 +3604,7 @@ name = "rustc_abi"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "rand 0.8.5",
+ "rand",
  "rand_xoshiro",
  "rustc_data_structures",
  "rustc_index",
@@ -3636,6 +3838,7 @@ dependencies = [
  "rustc_span",
  "rustc_symbol_mangling",
  "rustc_target",
+ "rustc_type_ir",
  "serde_json",
  "smallvec",
  "snap",
@@ -3770,6 +3973,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "serde",
  "serde_json",
  "termcolor",
@@ -3906,7 +4110,7 @@ dependencies = [
 name = "rustc_incremental"
 version = "0.0.0"
 dependencies = [
- "rand 0.8.5",
+ "rand",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -4226,6 +4430,8 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "serde",
+ "serde_json",
  "smallvec",
  "tracing",
 ]
@@ -4774,6 +4980,20 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
+[[package]]
+name = "sec1"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
+dependencies = [
+ "base16ct",
+ "der",
+ "generic-array",
+ "pkcs8",
+ "subtle",
+ "zeroize",
+]
+
 [[package]]
 name = "security-framework"
 version = "2.0.0"
@@ -4805,18 +5025,18 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
 
 [[package]]
 name = "semver"
-version = "1.0.12"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
@@ -4833,9 +5053,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4853,9 +5073,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
 dependencies = [
  "indexmap",
  "itoa",
@@ -4876,9 +5096,9 @@ dependencies = [
 
 [[package]]
 name = "sha2"
-version = "0.10.1"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
+checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -4906,6 +5126,16 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d"
 
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+dependencies = [
+ "digest",
+ "rand_core",
+]
+
 [[package]]
 name = "similar"
 version = "2.1.0"
@@ -5009,6 +5239,16 @@ dependencies = [
  "uuid",
 ]
 
+[[package]]
+name = "spki"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
 [[package]]
 name = "stable_deref_trait"
 version = "1.2.0"
@@ -5053,11 +5293,12 @@ dependencies = [
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
- "rand 0.7.3",
+ "rand",
+ "rand_xorshift",
  "rustc-demangle",
  "std_detect",
  "unwind",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
 ]
 
 [[package]]
@@ -5131,11 +5372,17 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
 [[package]]
 name = "syn"
-version = "1.0.102"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5203,9 +5450,9 @@ dependencies = [
 
 [[package]]
 name = "termcolor"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
 dependencies = [
  "winapi-util",
 ]
@@ -5309,6 +5556,8 @@ dependencies = [
  "lazy_static",
  "miropt-test-tools",
  "regex",
+ "semver",
+ "termcolor",
  "walkdir",
 ]
 
@@ -5326,6 +5575,33 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "time"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
+dependencies = [
+ "itoa",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+
+[[package]]
+name = "time-macros"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
+dependencies = [
+ "time-core",
+]
+
 [[package]]
 name = "tinystr"
 version = "0.7.0"
@@ -5494,7 +5770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
 dependencies = [
  "cfg-if",
- "rand 0.8.5",
+ "rand",
  "static_assertions",
 ]
 
@@ -5509,9 +5785,9 @@ dependencies = [
 
 [[package]]
 name = "typenum"
-version = "1.12.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
 
 [[package]]
 name = "ucd-parse"
@@ -5777,7 +6053,7 @@ version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
 dependencies = [
- "getrandom 0.2.8",
+ "getrandom",
 ]
 
 [[package]]
@@ -5818,12 +6094,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
-
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -5835,6 +6105,60 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -6027,6 +6351,12 @@ dependencies = [
  "synstructure",
 ]
 
+[[package]]
+name = "zeroize"
+version = "1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
+
 [[package]]
 name = "zerovec"
 version = "0.9.0"
index 1cec4a84480c43a4215d10ea2fc3f3b3d227f580..ce08d4edb567d05f1e108655c0fd56588913f00d 100644 (file)
@@ -4,6 +4,7 @@ members = [
   "library/std",
   "library/test",
   "src/rustdoc-json-types",
+  "src/tools/build_helper",
   "src/tools/cargotest",
   "src/tools/clippy",
   "src/tools/clippy/clippy_dev",
index 2b7edf2c3c90758a298267b15228246dc280fab0..ac39435a8c7fb9338a0f278452e2d8ff8afa525d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -20,22 +20,23 @@ Read ["Installation"] from [The Book].
 The Rust build system uses a Python script called `x.py` to build the compiler,
 which manages the bootstrapping process. It lives at the root of the project.
 
-The `x.py` command can be run directly on most systems in the following format:
+The `x.py` command can be run directly on most Unix systems in the following format:
 
 ```sh
 ./x.py <subcommand> [flags]
 ```
 
-This is how the documentation and examples assume you are running `x.py`.
-
-Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case, you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself:
+This is how the documentation and examples assume you are running `x.py`. Some alternative ways are:
 
 ```sh
-# Python 3
-python3 x.py <subcommand> [flags]
+# On a Unix shell if you don't have the necessary `python3` command
+./x <subcommand> [flags]
+
+# On the Windows Command Prompt (if .py files are configured to run Python)
+x.py <subcommand> [flags]
 
-# Python 2.7
-python2.7 x.py <subcommand> [flags]
+# You can also run Python yourself, e.g.:
+python x.py <subcommand> [flags]
 ```
 
 More information about `x.py` can be found
index 31596a1e9bf889ca1f684fcca0c20673add5c558..e656fb3740bbdf74a9301cd233a65208980886d8 100644 (file)
@@ -572,7 +572,7 @@ pub fn to_ty(&self) -> Option<P<Ty>> {
             PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()),
             // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
             PatKind::Ref(pat, mutbl) => {
-                pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?
+                pat.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
             }
             // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
             // when `P` can be reparsed as a type `T`.
@@ -1193,7 +1193,7 @@ pub fn to_ty(&self) -> Option<P<Ty>> {
             ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?,
 
             ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
-                expr.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?
+                expr.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
             }
 
             ExprKind::Repeat(expr, expr_len) => {
@@ -2031,7 +2031,7 @@ fn clone(&self) -> Self {
 impl Ty {
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
-        while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
             final_ty = ty;
         }
         final_ty
@@ -2058,7 +2058,7 @@ pub enum TyKind {
     /// A raw pointer (`*const T` or `*mut T`).
     Ptr(MutTy),
     /// A reference (`&'a T` or `&'a mut T`).
-    Rptr(Option<Lifetime>, MutTy),
+    Ref(Option<Lifetime>, MutTy),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(P<BareFnTy>),
     /// The never type (`!`).
@@ -2170,10 +2170,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 Ok(())
             }
             Self::Placeholder { operand_idx, modifier: Some(modifier), .. } => {
-                write!(f, "{{{}:{}}}", operand_idx, modifier)
+                write!(f, "{{{operand_idx}:{modifier}}}")
             }
             Self::Placeholder { operand_idx, modifier: None, .. } => {
-                write!(f, "{{{}}}", operand_idx)
+                write!(f, "{{{operand_idx}}}")
             }
         }
     }
@@ -2185,7 +2185,7 @@ pub fn to_string(s: &[Self]) -> String {
         use fmt::Write;
         let mut out = String::new();
         for p in s.iter() {
-            let _ = write!(out, "{}", p);
+            let _ = write!(out, "{p}");
         }
         out
     }
@@ -2286,7 +2286,7 @@ pub fn to_self(&self) -> Option<ExplicitSelf> {
             if ident.name == kw::SelfLower {
                 return match self.ty.kind {
                     TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
-                    TyKind::Rptr(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
+                    TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
                         Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
                     }
                     _ => Some(respan(
@@ -2319,7 +2319,7 @@ pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Par
                 Mutability::Not,
                 P(Ty {
                     id: DUMMY_NODE_ID,
-                    kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
+                    kind: TyKind::Ref(lt, MutTy { ty: infer_ty, mutbl }),
                     span,
                     tokens: None,
                 }),
@@ -2743,8 +2743,19 @@ pub fn span_with_attributes(&self) -> Span {
 /// `extern` qualifier on a function item or function type.
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
+    /// No explicit extern keyword was used
+    ///
+    /// E.g. `fn foo() {}`
     None,
+    /// An explicit extern keyword was used, but with implicit ABI
+    ///
+    /// E.g. `extern fn foo() {}`
+    ///
+    /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
     Implicit(Span),
+    /// An explicit extern keyword was used with an explicit ABI
+    ///
+    /// E.g. `extern "C" fn foo() {}`
     Explicit(StrLit, Span),
 }
 
@@ -2763,9 +2774,13 @@ pub fn from_abi(abi: Option<StrLit>, span: Span) -> Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
+    /// The `unsafe` keyword, if any
     pub unsafety: Unsafe,
+    /// The `async` keyword, if any
     pub asyncness: Async,
+    /// The `const` keyword, if any
     pub constness: Const,
+    /// The `extern` keyword and corresponding ABI string, if any
     pub ext: Extern,
 }
 
index 1b31be07f7ad1b1cc8cdb93b80fc463ab7d8e64b..4dc9c30a2c807a2050c8fb72638cb2b3e4a4d2a8 100644 (file)
@@ -214,7 +214,7 @@ fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         match &self.kind {
             AttrKind::Normal(normal) => normal.tokens.as_ref(),
             kind @ AttrKind::DocComment(..) => {
-                panic!("Called tokens on doc comment attr {:?}", kind)
+                panic!("Called tokens on doc comment attr {kind:?}")
             }
         }
     }
@@ -222,7 +222,7 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
         Some(match &mut self.kind {
             AttrKind::Normal(normal) => &mut normal.tokens,
             kind @ AttrKind::DocComment(..) => {
-                panic!("Called tokens_mut on doc comment attr {:?}", kind)
+                panic!("Called tokens_mut on doc comment attr {kind:?}")
             }
         })
     }
index d99f6ed2c1cd3d842964559774669b83e86dc75b..c6b6207b3186e85442b1c388c221b6974b0306b3 100644 (file)
@@ -310,7 +310,7 @@ pub fn tokens(&self) -> TokenStream {
             AttrKind::Normal(normal) => normal
                 .tokens
                 .as_ref()
-                .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
+                .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
                 .to_attr_token_stream()
                 .to_tokenstream(),
             &AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
index 1976e4ad3c9fc73e4fe06f704990a7bcebacff7c..35939496348988af0e5d3c7f2aaac62120978490 100644 (file)
@@ -9,8 +9,8 @@ pub enum AllocatorKind {
 impl AllocatorKind {
     pub fn fn_name(&self, base: Symbol) -> String {
         match *self {
-            AllocatorKind::Global => format!("__rg_{}", base),
-            AllocatorKind::Default => format!("__rdl_{}", base),
+            AllocatorKind::Global => format!("__rg_{base}"),
+            AllocatorKind::Default => format!("__rdl_{base}"),
         }
     }
 }
index a45ee6067bbaedb5c541d91dd2ccff91f23228e1..c572171e8f44393c65f7eba5ce499cd2e8286672 100644 (file)
@@ -459,7 +459,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
         TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
         TyKind::Slice(ty) => vis.visit_ty(ty),
         TyKind::Ptr(mt) => vis.visit_mt(mt),
-        TyKind::Rptr(lt, mt) => {
+        TyKind::Ref(lt, mt) => {
             visit_opt(lt, |lt| noop_visit_lifetime(lt, vis));
             vis.visit_mt(mt);
         }
index 5b6cf30fa96e37f416ba2edcf8cc1545d4731118..f947ae4d05732f341632abeddcc61af32c7fb07c 100644 (file)
@@ -125,27 +125,27 @@ impl fmt::Display for Lit {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let Lit { kind, symbol, suffix } = *self;
         match kind {
-            Byte => write!(f, "b'{}'", symbol)?,
-            Char => write!(f, "'{}'", symbol)?,
-            Str => write!(f, "\"{}\"", symbol)?,
+            Byte => write!(f, "b'{symbol}'")?,
+            Char => write!(f, "'{symbol}'")?,
+            Str => write!(f, "\"{symbol}\"")?,
             StrRaw(n) => write!(
                 f,
                 "r{delim}\"{string}\"{delim}",
                 delim = "#".repeat(n as usize),
                 string = symbol
             )?,
-            ByteStr => write!(f, "b\"{}\"", symbol)?,
+            ByteStr => write!(f, "b\"{symbol}\"")?,
             ByteStrRaw(n) => write!(
                 f,
                 "br{delim}\"{string}\"{delim}",
                 delim = "#".repeat(n as usize),
                 string = symbol
             )?,
-            Integer | Float | Bool | Err => write!(f, "{}", symbol)?,
+            Integer | Float | Bool | Err => write!(f, "{symbol}")?,
         }
 
         if let Some(suffix) = suffix {
-            write!(f, "{}", suffix)?;
+            write!(f, "{suffix}")?;
         }
 
         Ok(())
@@ -756,7 +756,7 @@ pub fn glue(&self, joint: &Token) -> Option<Token> {
                 _ => return None,
             },
             SingleQuote => match joint.kind {
-                Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
+                Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))),
                 _ => return None,
             },
 
index 29a5eb4b7c509260a9034296eec158af8abcb123..fabd43a1618a4387fa8af8680fe8a52f17af90d1 100644 (file)
@@ -258,8 +258,7 @@ pub fn to_tokenstream(&self) -> TokenStream {
 
                         assert!(
                             found,
-                            "Failed to find trailing delimited group in: {:?}",
-                            target_tokens
+                            "Failed to find trailing delimited group in: {target_tokens:?}"
                         );
                     }
                     let mut flat: SmallVec<[_; 1]> = SmallVec::new();
index 0daeecb53a8b9d88a1432fa05440360de7096cad..74b842ac96eacd935fe92d2eeae6f22cb2c45927 100644 (file)
@@ -34,7 +34,7 @@ pub enum LitError {
     InvalidIntSuffix,
     InvalidFloatSuffix,
     NonDecimalFloat(u32),
-    IntTooLarge,
+    IntTooLarge(u32),
 }
 
 impl LitKind {
@@ -168,7 +168,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             LitKind::Byte(b) => {
                 let b: String = ascii::escape_default(b).map(Into::<char>::into).collect();
-                write!(f, "b'{}'", b)?;
+                write!(f, "b'{b}'")?;
             }
             LitKind::Char(ch) => write!(f, "'{}'", escape_char_symbol(ch))?,
             LitKind::Str(sym, StrStyle::Cooked) => write!(f, "\"{}\"", escape_string_symbol(sym))?,
@@ -192,7 +192,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 )?;
             }
             LitKind::Int(n, ty) => {
-                write!(f, "{}", n)?;
+                write!(f, "{n}")?;
                 match ty {
                     ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?,
                     ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?,
@@ -200,7 +200,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 }
             }
             LitKind::Float(symbol, ty) => {
-                write!(f, "{}", symbol)?;
+                write!(f, "{symbol}")?;
                 match ty {
                     ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?,
                     ast::LitFloatType::Unsuffixed => {}
@@ -333,6 +333,6 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
         // but these kinds of errors are already reported by the lexer.
         let from_lexer =
             base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
-        if from_lexer { LitError::LexerError } else { LitError::IntTooLarge }
+        if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) }
     })
 }
index 991eb489f6ba3ee115fbf7f8b8dcf691226adf48..df7145a722a46e52c9de6072d6467d7a525f0b09 100644 (file)
@@ -92,7 +92,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
 #[derive(Copy, Clone, Debug)]
 pub enum LifetimeCtxt {
     /// Appears in a reference type.
-    Rptr,
+    Ref,
     /// Appears as a bound on a type or another lifetime.
     Bound,
     /// Appears as a generic argument.
@@ -396,8 +396,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
     match &typ.kind {
         TyKind::Slice(ty) | TyKind::Paren(ty) => visitor.visit_ty(ty),
         TyKind::Ptr(mutable_type) => visitor.visit_ty(&mutable_type.ty),
-        TyKind::Rptr(opt_lifetime, mutable_type) => {
-            walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Rptr);
+        TyKind::Ref(opt_lifetime, mutable_type) => {
+            walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
             visitor.visit_ty(&mutable_type.ty)
         }
         TyKind::Tup(tuple_element_types) => {
index dfef6ec70fcf772c5f1186200f76709dff5cd5e2..941d3179587ebea510fc29bd4049f26212eb75c9 100644 (file)
@@ -104,7 +104,7 @@ pub(crate) fn lower_inline_asm(
                     Err(supported_abis) => {
                         let mut abis = format!("`{}`", supported_abis[0]);
                         for m in &supported_abis[1..] {
-                            let _ = write!(abis, ", `{}`", m);
+                            let _ = write!(abis, ", `{m}`");
                         }
                         self.tcx.sess.emit_err(InvalidAbiClobberAbi {
                             abi_span: *abi_span,
@@ -262,7 +262,7 @@ pub(crate) fn lower_inline_asm(
                             let sub = if !valid_modifiers.is_empty() {
                                 let mut mods = format!("`{}`", valid_modifiers[0]);
                                 for m in &valid_modifiers[1..] {
-                                    let _ = write!(mods, ", `{}`", m);
+                                    let _ = write!(mods, ", `{m}`");
                                 }
                                 InvalidAsmTemplateModifierRegClassSub::SupportModifier {
                                     class_name: class.name(),
index 4abb1d90f4485e6a3998da2ef721c69d858eb1b4..ea30bed5ace4f208584812a885da055d96f98c42 100644 (file)
@@ -1051,7 +1051,7 @@ fn lower_maybe_async_body(
                     }
                     _ => {
                         // Replace the ident for bindings that aren't simple.
-                        let name = format!("__arg{}", index);
+                        let name = format!("__arg{index}");
                         let ident = Ident::from_str(&name);
 
                         (ident, false)
@@ -1316,6 +1316,8 @@ fn lower_generics<T>(
                 param.id,
                 &param.kind,
                 &param.bounds,
+                param.colon_span,
+                generics.span,
                 itctx,
                 PredicateOrigin::GenericParam,
             )
@@ -1365,6 +1367,8 @@ pub(super) fn lower_generic_bound_predicate(
         id: NodeId,
         kind: &GenericParamKind,
         bounds: &[GenericBound],
+        colon_span: Option<Span>,
+        parent_span: Span,
         itctx: &ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
@@ -1377,21 +1381,17 @@ pub(super) fn lower_generic_bound_predicate(
 
         let ident = self.lower_ident(ident);
         let param_span = ident.span;
-        let span = bounds
-            .iter()
-            .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
-                let bound_span = bound.span();
-                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
-                // as we use this method to get a span appropriate for suggestions.
-                if !bound_span.can_be_used_for_suggestions() {
-                    None
-                } else if let Some(span) = span {
-                    Some(span.to(bound_span))
-                } else {
-                    Some(bound_span)
-                }
-            })
-            .unwrap_or(param_span.shrink_to_hi());
+
+        // Reconstruct the span of the entire predicate from the individual generic bounds.
+        let span_start = colon_span.unwrap_or_else(|| param_span.shrink_to_hi());
+        let span = bounds.iter().fold(span_start, |span_accum, bound| {
+            match bound.span().find_ancestor_inside(parent_span) {
+                Some(bound_span) => span_accum.to(bound_span),
+                None => span_accum,
+            }
+        });
+        let span = self.lower_span(span);
+
         match kind {
             GenericParamKind::Const { .. } => None,
             GenericParamKind::Type { .. } => {
index a089510493effe6425a3702bd8029f2c65d19967..2e135aafb1e0f36856dce96b87ab3251424a6a50 100644 (file)
@@ -296,7 +296,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
             ImplTraitPosition::ImplReturn => "`impl` method return",
         };
 
-        write!(f, "{}", name)
+        write!(f, "{name}")
     }
 }
 
@@ -503,7 +503,7 @@ fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
 
     fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
         self.orig_opt_local_def_id(node)
-            .unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+            .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
@@ -524,7 +524,7 @@ fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
-        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
     /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
@@ -776,7 +776,7 @@ fn mark_span_with_reason(
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
+        if self.tcx.sess.opts.incremental_relative_spans() {
             span.with_parent(Some(self.current_hir_id_owner.def_id))
         } else {
             // Do not make spans relative when not using incremental compilation.
@@ -1238,7 +1238,7 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
             TyKind::Err => hir::TyKind::Err,
             TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
-            TyKind::Rptr(region, mt) => {
+            TyKind::Ref(region, mt) => {
                 let region = region.unwrap_or_else(|| {
                     let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
                         self.resolver.get_lifetime_res(t.id)
@@ -1252,7 +1252,7 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
                     Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
                 });
                 let lifetime = self.lower_lifetime(&region);
-                hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
+                hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(f) => {
                 let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
@@ -1771,7 +1771,7 @@ fn lower_fn_decl(
                     // Given we are only considering `ImplicitSelf` types, we needn't consider
                     // the case where we have a mutable pattern to a reference as that would
                     // no longer be an `ImplicitSelf`.
-                    TyKind::Rptr(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
+                    TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
                         hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef,
                         hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef,
                     },
@@ -2197,7 +2197,7 @@ fn lower_generic_param_kind(
     fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
         let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path,
-            qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
+            qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
         };
         hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) }
     }
@@ -2245,6 +2245,7 @@ fn lower_generic_and_bounds(
     ) -> (hir::GenericParam<'hir>, Option<hir::WherePredicate<'hir>>, hir::TyKind<'hir>) {
         // Add a definition for the in-band `Param`.
         let def_id = self.local_def_id(node_id);
+        let span = self.lower_span(span);
 
         // Set the name to `impl Bound1 + Bound2`.
         let param = hir::GenericParam {
@@ -2252,7 +2253,7 @@ fn lower_generic_and_bounds(
             def_id,
             name: ParamName::Plain(self.lower_ident(ident)),
             pure_wrt_drop: false,
-            span: self.lower_span(span),
+            span,
             kind: hir::GenericParamKind::Type { default: None, synthetic: true },
             colon_span: None,
         };
@@ -2262,6 +2263,8 @@ fn lower_generic_and_bounds(
             node_id,
             &GenericParamKind::Type { default: None },
             bounds,
+            /* colon_span */ None,
+            span,
             &ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
@@ -2271,7 +2274,7 @@ fn lower_generic_and_bounds(
         let ty = hir::TyKind::Path(hir::QPath::Resolved(
             None,
             self.arena.alloc(hir::Path {
-                span: self.lower_span(span),
+                span,
                 res,
                 segments:
                     arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
index 914fc5f58da140a7110f3a380b9e0788ad4db42c..3989fc486193e6d25922c6100b0ba91917f17e6d 100644 (file)
@@ -83,7 +83,7 @@ fn visit_ty(&mut self, t: &'ast Ty) {
                 visit::walk_ty(self, t);
                 self.current_binders.pop();
             }
-            TyKind::Rptr(None, _) => {
+            TyKind::Ref(None, _) => {
                 self.record_elided_anchor(t.id, t.span);
                 visit::walk_ty(self, t);
             }
index d0e4761a10db8978519b3326d5718ead15bf29b7..6a8064b0e874e84fc7731af56d705b41457d861d 100644 (file)
@@ -191,23 +191,23 @@ fn doc_comment_to_string(
     data: Symbol,
 ) -> String {
     match (comment_kind, attr_style) {
-        (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
-        (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
-        (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
-        (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
+        (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"),
+        (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"),
+        (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"),
+        (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"),
     }
 }
 
 pub fn literal_to_string(lit: token::Lit) -> String {
     let token::Lit { kind, symbol, suffix } = lit;
     let mut out = match kind {
-        token::Byte => format!("b'{}'", symbol),
-        token::Char => format!("'{}'", symbol),
-        token::Str => format!("\"{}\"", symbol),
+        token::Byte => format!("b'{symbol}'"),
+        token::Char => format!("'{symbol}'"),
+        token::Str => format!("\"{symbol}\""),
         token::StrRaw(n) => {
             format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
         }
-        token::ByteStr => format!("b\"{}\"", symbol),
+        token::ByteStr => format!("b\"{symbol}\""),
         token::ByteStrRaw(n) => {
             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
         }
@@ -1025,7 +1025,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
                 self.word("*");
                 self.print_mt(mt, true);
             }
-            ast::TyKind::Rptr(lifetime, mt) => {
+            ast::TyKind::Ref(lifetime, mt) => {
                 self.word("&");
                 self.print_opt_lifetime(lifetime);
                 self.print_mt(mt, false);
index 5b6a07721e2bbdb605710cfb2a701f5e90078584..bf2c73a66a2cbb435e605af1c68b9321c6ecbbaa 100644 (file)
@@ -411,9 +411,9 @@ pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
             ast::VisibilityKind::Restricted { path, shorthand, .. } => {
                 let path = Self::to_string(|s| s.print_path(path, false, 0));
                 if *shorthand && (path == "crate" || path == "self" || path == "super") {
-                    self.word_nbsp(format!("pub({})", path))
+                    self.word_nbsp(format!("pub({path})"))
                 } else {
-                    self.word_nbsp(format!("pub(in {})", path))
+                    self.word_nbsp(format!("pub(in {path})"))
                 }
             }
             ast::VisibilityKind::Inherited => {}
index ab5e19050ead2ffbb0a0d475c69d985ec86fb588..40531c1c164f207609395f15cdfcaf1c14dab9d0 100644 (file)
@@ -619,7 +619,7 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Fe
 fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
     let (cfg, feature, has_feature) = gated_cfg;
     if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
-        let explain = format!("`cfg({})` is experimental and subject to change", cfg);
+        let explain = format!("`cfg({cfg})` is experimental and subject to change");
         feature_err(sess, *feature, cfg_span, &explain).emit();
     }
 }
@@ -975,7 +975,7 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
 }
 
 pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
-    assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {:?}", attr);
+    assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
     use ReprAttr::*;
     let mut acc = Vec::new();
     let diagnostic = &sess.parse_sess.span_diagnostic;
index 91c6bcb08a079db59feaaa82615000fcef6fc0a9..3ba7a3c5336b247de22203ade044a36814d5fcbc 100644 (file)
@@ -51,7 +51,7 @@ pub(crate) struct UnknownMetaItem<'a> {
 // Manual implementation to be able to format `expected` items correctly.
 impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
+        let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
         let mut diag = handler.struct_span_err_with_code(
             self.span,
             fluent::attr_unknown_meta_item,
index 01be379120dc7483c088daa4005b744bb386dfb8..a4943d112042dc212d419f0247933a88cecb158a 100644 (file)
@@ -12,7 +12,7 @@ pub(crate) fn cannot_move_when_borrowed(
         place: &str,
         borrow_place: &str,
         value_place: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
             place,
             span,
@@ -28,7 +28,7 @@ pub(crate) fn cannot_use_when_mutably_borrowed(
         desc: &str,
         borrow_span: Span,
         borrow_desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             span,
@@ -50,7 +50,7 @@ pub(crate) fn cannot_mutably_borrow_multiply(
         old_loan_span: Span,
         old_opt_via: &str,
         old_load_end_span: Option<Span>,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let via =
             |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
         let mut err = struct_span_err!(
@@ -98,7 +98,7 @@ pub(crate) fn cannot_uniquely_borrow_by_two_closures(
         desc: &str,
         old_loan_span: Span,
         old_load_end_span: Option<Span>,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             new_loan_span,
@@ -269,7 +269,7 @@ pub(crate) fn cannot_assign(
         &self,
         span: Span,
         desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
     }
 
@@ -348,7 +348,7 @@ pub(crate) fn cannot_borrow_path_as_mutable_because(
         span: Span,
         path: &str,
         reason: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
     }
 
@@ -359,7 +359,7 @@ pub(crate) fn cannot_mutate_in_immutable_section(
         immutable_place: &str,
         immutable_section: &str,
         action: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             mutate_span,
@@ -378,7 +378,7 @@ pub(crate) fn cannot_borrow_across_generator_yield(
         &self,
         span: Span,
         yield_span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             span,
@@ -392,7 +392,7 @@ pub(crate) fn cannot_borrow_across_generator_yield(
     pub(crate) fn cannot_borrow_across_destructor(
         &self,
         borrow_span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(
             self,
             borrow_span,
@@ -405,7 +405,7 @@ pub(crate) fn path_does_not_live_long_enough(
         &self,
         span: Span,
         path: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
     }
 
@@ -415,7 +415,7 @@ pub(crate) fn cannot_return_reference_to_local(
         return_kind: &str,
         reference_desc: &str,
         path_desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             span,
@@ -440,15 +440,14 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
         closure_kind: &str,
         borrowed_path: &str,
         capture_span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+        scope: &str,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             closure_span,
             E0373,
-            "{} may outlive the current function, but it borrows {}, which is owned by the current \
-             function",
-            closure_kind,
-            borrowed_path,
+            "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
+             which is owned by the current {scope}",
         );
         err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
             .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
@@ -458,14 +457,14 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
     pub(crate) fn thread_local_value_does_not_live_long_enough(
         &self,
         span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
     }
 
     pub(crate) fn temporary_value_borrowed_for_too_long(
         &self,
         span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
     }
 
index 8d5c5a7124f88aeee0e472d5557d80b74cbea1ad..eda5588a4d52ec09a04071809ce40de54458fac7 100644 (file)
@@ -156,7 +156,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 err.span_note(
                     MultiSpan::from_spans(reinit_spans),
                     &if reinits <= 3 {
-                        format!("these {} reinitializations might get skipped", reinits)
+                        format!("these {reinits} reinitializations might get skipped")
                     } else {
                         format!(
                             "these 3 reinitializations and {} other{} might get skipped",
@@ -194,7 +194,13 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
 
                 if !seen_spans.contains(&move_span) {
                     if !closure {
-                        self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern);
+                        self.suggest_ref_or_clone(
+                            mpi,
+                            move_span,
+                            &mut err,
+                            &mut in_pattern,
+                            move_spans,
+                        );
                     }
 
                     self.explain_captures(
@@ -219,9 +225,8 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 err.span_label(
                     span,
                     format!(
-                        "value {} here after {}move",
+                        "value {} here after {partial_str}move",
                         desired_action.as_verb_in_past_tense(),
-                        partial_str
                     ),
                 );
             }
@@ -251,7 +256,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                         &format!(
                             "consider creating a fresh reborrow of {} here",
                             self.describe_place(moved_place)
-                                .map(|n| format!("`{}`", n))
+                                .map(|n| format!("`{n}`"))
                                 .unwrap_or_else(|| "the mutable reference".to_string()),
                         ),
                         "&mut *",
@@ -265,7 +270,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
             );
             let note_msg = match opt_name {
-                Some(name) => format!("`{}`", name),
+                Some(name) => format!("`{name}`"),
                 None => "value".to_owned(),
             };
             if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
@@ -291,9 +296,8 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
             } = use_spans
             {
                 err.note(&format!(
-                    "{} occurs due to deref coercion to `{}`",
+                    "{} occurs due to deref coercion to `{deref_target_ty}`",
                     desired_action.as_noun(),
-                    deref_target_ty
                 ));
 
                 // Check first whether the source is accessible (issue #87060)
@@ -312,6 +316,7 @@ fn suggest_ref_or_clone(
         move_span: Span,
         err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
         in_pattern: &mut bool,
+        move_spans: UseSpans<'_>,
     ) {
         struct ExpressionFinder<'hir> {
             expr_span: Span,
@@ -387,7 +392,7 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
                     }
                 }
                 let typeck = self.infcx.tcx.typeck(self.mir_def_id());
-                let hir_id = hir.get_parent_node(expr.hir_id);
+                let hir_id = hir.parent_id(expr.hir_id);
                 if let Some(parent) = hir.find(hir_id) {
                     let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
                         && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
@@ -440,6 +445,11 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
                         ) = call_expr.kind
                     {
                         // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
+                    } else if let UseSpans::FnSelfUse {
+                        kind: CallKind::Normal { .. },
+                        ..
+                    } = move_spans {
+                        // We already suggest cloning for these cases in `explain_captures`.
                     } else {
                         self.suggest_cloning(err, ty, move_span);
                     }
@@ -515,26 +525,21 @@ fn report_use_of_uninitialized(
             // that are *partially* initialized by assigning to a field of an uninitialized
             // binding. We differentiate between them for more accurate wording here.
             "isn't fully initialized"
-        } else if spans
-            .iter()
-            .filter(|i| {
-                // We filter these to avoid misleading wording in cases like the following,
-                // where `x` has an `init`, but it is in the same place we're looking at:
-                // ```
-                // let x;
-                // x += 1;
-                // ```
-                !i.contains(span)
-                    // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
-                        && !visitor
-                            .errors
-                            .iter()
-                            .map(|(sp, _)| *sp)
-                            .any(|sp| span < sp && !sp.contains(span))
-            })
-            .count()
-            == 0
-        {
+        } else if !spans.iter().any(|i| {
+            // We filter these to avoid misleading wording in cases like the following,
+            // where `x` has an `init`, but it is in the same place we're looking at:
+            // ```
+            // let x;
+            // x += 1;
+            // ```
+            !i.contains(span)
+            // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
+            && !visitor
+                .errors
+                .iter()
+                .map(|(sp, _)| *sp)
+                .any(|sp| span < sp && !sp.contains(span))
+        }) {
             show_assign_sugg = true;
             "isn't initialized"
         } else {
@@ -1416,6 +1421,21 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
             //
             // then just use the normal error. The closure isn't escaping
             // and `move` will not help here.
+            (
+                Some(name),
+                BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
+            ) => self.report_escaping_closure_capture(
+                borrow_spans,
+                borrow_span,
+                &RegionName {
+                    name: self.synthesize_region_name(),
+                    source: RegionNameSource::Static,
+                },
+                ConstraintCategory::CallArgument(None),
+                var_or_use_span,
+                &format!("`{}`", name),
+                "block",
+            ),
             (
                 Some(name),
                 BorrowExplanation::MustBeValidFor {
@@ -1436,6 +1456,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
                     category,
                     span,
                     &format!("`{}`", name),
+                    "function",
                 ),
             (
                 name,
@@ -1888,6 +1909,7 @@ fn try_report_cannot_return_reference_to_local(
         Some(err)
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn report_escaping_closure_capture(
         &mut self,
         use_span: UseSpans<'tcx>,
@@ -1896,6 +1918,7 @@ fn report_escaping_closure_capture(
         category: ConstraintCategory<'tcx>,
         constraint_span: Span,
         captured_var: &str,
+        scope: &str,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         let tcx = self.infcx.tcx;
         let args_span = use_span.args_or_use();
@@ -1926,8 +1949,13 @@ fn report_escaping_closure_capture(
             None => "closure",
         };
 
-        let mut err =
-            self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
+        let mut err = self.cannot_capture_in_long_lived_closure(
+            args_span,
+            kind,
+            captured_var,
+            var_span,
+            scope,
+        );
         err.span_suggestion_verbose(
             sugg_span,
             &format!(
@@ -1949,10 +1977,10 @@ fn report_escaping_closure_capture(
                 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
                     err.note(
                         "async blocks are not executed immediately and must either take a \
-                    reference or ownership of outside variables they use",
+                         reference or ownership of outside variables they use",
                     );
                 } else {
-                    let msg = format!("function requires argument type to outlive `{}`", fr_name);
+                    let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
                     err.span_note(constraint_span, &msg);
                 }
             }
@@ -2669,7 +2697,7 @@ fn annotate_fn_sig(
                             // Need to use the `rustc_middle::ty` types to compare against the
                             // `return_region`. Then use the `rustc_hir` type to get only
                             // the lifetime span.
-                            if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
+                            if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
                                 // With access to the lifetime, we can get
                                 // the span of it.
                                 arguments.push((*argument, lifetime.ident.span));
@@ -2690,7 +2718,7 @@ fn annotate_fn_sig(
                 let return_ty = sig.output().skip_binder();
                 let mut return_span = fn_decl.output.span();
                 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
-                    if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
+                    if let hir::TyKind::Ref(lifetime, _) = ty.kind {
                         return_span = lifetime.ident.span;
                     }
                 }
index 00f5e8a83972f9c6456c51635867e2a7bfa59227..2095747097b7660870ecdff8b32fc8820525652b 100644 (file)
@@ -77,7 +77,7 @@ pub(crate) fn add_explanation_to_diagnostic(
                     if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
                         err.span_label(
                             var_or_use_span,
-                            format!("{}borrow later {}", borrow_desc, message),
+                            format!("{borrow_desc}borrow later {message}"),
                         );
                     }
                 } else {
@@ -90,7 +90,7 @@ pub(crate) fn add_explanation_to_diagnostic(
                         let capture_kind_label = message;
                         err.span_label(
                             var_or_use_span,
-                            format!("{}borrow later {}", borrow_desc, capture_kind_label),
+                            format!("{borrow_desc}borrow later {capture_kind_label}"),
                         );
                         err.span_label(path_span, path_label);
                     }
@@ -110,7 +110,7 @@ pub(crate) fn add_explanation_to_diagnostic(
                 };
                 // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
                 if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
-                    err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+                    err.span_label(var_or_use_span, format!("{borrow_desc}{message}"));
                 } else {
                     // path_span must be `Some` as otherwise the if condition is true
                     let path_span = path_span.unwrap();
@@ -121,7 +121,7 @@ pub(crate) fn add_explanation_to_diagnostic(
                         let capture_kind_label = message;
                         err.span_label(
                             var_or_use_span,
-                            format!("{}borrow later {}", borrow_desc, capture_kind_label),
+                            format!("{borrow_desc}borrow later {capture_kind_label}"),
                         );
                         err.span_label(path_span, path_label);
                     }
@@ -160,12 +160,8 @@ pub(crate) fn add_explanation_to_diagnostic(
                 match local_names[dropped_local] {
                     Some(local_name) if !local_decl.from_compiler_desugaring() => {
                         let message = format!(
-                            "{B}borrow might be used here, when `{LOC}` is dropped \
-                             and runs the {DTOR} for {TYPE}",
-                            B = borrow_desc,
-                            LOC = local_name,
-                            TYPE = type_desc,
-                            DTOR = dtor_desc
+                            "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \
+                             and runs the {dtor_desc} for {type_desc}",
                         );
                         err.span_label(body.source_info(drop_loc).span, message);
 
@@ -180,18 +176,14 @@ pub(crate) fn add_explanation_to_diagnostic(
                         err.span_label(
                             local_decl.source_info.span,
                             format!(
-                                "a temporary with access to the {B}borrow \
+                                "a temporary with access to the {borrow_desc}borrow \
                                  is created here ...",
-                                B = borrow_desc
                             ),
                         );
                         let message = format!(
-                            "... and the {B}borrow might be used here, \
+                            "... and the {borrow_desc}borrow might be used here, \
                              when that temporary is dropped \
-                             and runs the {DTOR} for {TYPE}",
-                            B = borrow_desc,
-                            TYPE = type_desc,
-                            DTOR = dtor_desc
+                             and runs the {dtor_desc} for {type_desc}",
                         );
                         err.span_label(body.source_info(drop_loc).span, message);
 
@@ -249,20 +241,16 @@ pub(crate) fn add_explanation_to_diagnostic(
                     err.span_label(
                         span,
                         format!(
-                            "{}requires that `{}` is borrowed for `{}`",
+                            "{}requires that `{desc}` is borrowed for `{region_name}`",
                             category.description(),
-                            desc,
-                            region_name,
                         ),
                     );
                 } else {
                     err.span_label(
                         span,
                         format!(
-                            "{}requires that {}borrow lasts for `{}`",
+                            "{}requires that {borrow_desc}borrow lasts for `{region_name}`",
                             category.description(),
-                            borrow_desc,
-                            region_name,
                         ),
                     );
                 };
@@ -296,15 +284,14 @@ fn add_lifetime_bound_suggestion_to_diagnostic(
                 if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
 
             let msg = format!(
-                "you can add a bound to the {}to make it last less than `'static` and match `{}`",
+                "you can add a bound to the {}to make it last less than `'static` and match `{region_name}`",
                 category.description(),
-                region_name,
             );
 
             err.span_suggestion_verbose(
                 span.shrink_to_hi(),
                 &msg,
-                format!(" + {}", suggestable_name),
+                format!(" + {suggestable_name}"),
                 Applicability::Unspecified,
             );
         }
@@ -444,6 +431,7 @@ pub(crate) fn explain_why_borrow_contains_point(
     /// First span returned points to the location of the conflicting use
     /// Second span if `Some` is returned in the case of closures and points
     /// to the use of the path
+    #[instrument(level = "debug", skip(self))]
     fn later_use_kind(
         &self,
         borrow: &BorrowData<'tcx>,
@@ -461,11 +449,18 @@ fn later_use_kind(
                 let block = &self.body.basic_blocks[location.block];
 
                 let kind = if let Some(&Statement {
-                    kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
+                    kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
                     ..
                 }) = block.statements.get(location.statement_index)
                 {
-                    LaterUseKind::FakeLetRead
+                    if let Some(l) = place.as_local()
+                        && let local_decl = &self.body.local_decls[l]
+                        && local_decl.ty.is_closure()
+                    {
+                        LaterUseKind::ClosureCapture
+                    } else {
+                        LaterUseKind::FakeLetRead
+                    }
                 } else if self.was_captured_by_trait_object(borrow) {
                     LaterUseKind::TraitCapture
                 } else if location.statement_index == block.statements.len() {
index cbd590052008c14a46f3ab0b099ea517ef6f7ce9..1b40b7143cbb6b671ba2faec06326c362a669de8 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::GeneratorKind;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{
+    type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
+};
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
@@ -400,8 +403,7 @@ pub(super) fn note_type_does_not_implement_copy(
         move_prefix: &str,
     ) {
         let message = format!(
-            "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
-            move_prefix, place_desc, ty,
+            "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait",
         );
         if let Some(span) = span {
             err.span_label(span, message);
@@ -736,11 +738,11 @@ pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
             BorrowedContentSource::OverloadedDeref(ty) => ty
                 .ty_adt_def()
                 .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
-                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
                     _ => None,
                 })
-                .unwrap_or_else(|| format!("dereference of `{}`", ty)),
-            BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
+                .unwrap_or_else(|| format!("dereference of `{ty}`")),
+            BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
         }
     }
 
@@ -766,11 +768,11 @@ pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
             BorrowedContentSource::OverloadedDeref(ty) => ty
                 .ty_adt_def()
                 .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
-                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
                     _ => None,
                 })
-                .unwrap_or_else(|| format!("dereference of `{}`", ty)),
-            BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
+                .unwrap_or_else(|| format!("dereference of `{ty}`")),
+            BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
         }
     }
 
@@ -1030,7 +1032,7 @@ fn explain_captures(
         if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
             let place_name = self
                 .describe_place(moved_place.as_ref())
-                .map(|n| format!("`{}`", n))
+                .map(|n| format!("`{n}`"))
                 .unwrap_or_else(|| "value".to_owned());
             match kind {
                 CallKind::FnCall { fn_trait_id, .. }
@@ -1039,8 +1041,7 @@ fn explain_captures(
                     err.span_label(
                         fn_call_span,
                         &format!(
-                            "{} {}moved due to this call{}",
-                            place_name, partially_str, loop_message
+                            "{place_name} {partially_str}moved due to this call{loop_message}",
                         ),
                     );
                     err.span_note(
@@ -1053,8 +1054,7 @@ fn explain_captures(
                     err.span_label(
                         fn_call_span,
                         &format!(
-                            "{} {}moved due to usage in operator{}",
-                            place_name, partially_str, loop_message
+                            "{place_name} {partially_str}moved due to usage in operator{loop_message}",
                         ),
                     );
                     if self.fn_self_span_reported.insert(fn_span) {
@@ -1066,18 +1066,16 @@ fn explain_captures(
                 }
                 CallKind::Normal { self_arg, desugaring, method_did } => {
                     let self_arg = self_arg.unwrap();
+                    let tcx = self.infcx.tcx;
                     if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
-                        let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
-                        let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+                        let ty = moved_place.ty(self.body, tcx).ty;
+                        let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
                             Some(def_id) => {
                                 let infcx = self.infcx.tcx.infer_ctxt().build();
                                 type_known_to_meet_bound_modulo_regions(
                                     &infcx,
                                     self.param_env,
-                                    infcx.tcx.mk_imm_ref(
-                                        infcx.tcx.lifetimes.re_erased,
-                                        infcx.tcx.erase_regions(ty),
-                                    ),
+                                    tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
                                     def_id,
                                     DUMMY_SP,
                                 )
@@ -1088,9 +1086,8 @@ fn explain_captures(
                             err.span_suggestion_verbose(
                                 move_span.shrink_to_lo(),
                                 &format!(
-                                    "consider iterating over a slice of the `{}`'s content to \
+                                    "consider iterating over a slice of the `{ty}`'s content to \
                                      avoid moving into the `for` loop",
-                                    ty,
                                 ),
                                 "&",
                                 Applicability::MaybeIncorrect,
@@ -1100,8 +1097,7 @@ fn explain_captures(
                         err.span_label(
                             fn_call_span,
                             &format!(
-                                "{} {}moved due to this implicit call to `.into_iter()`{}",
-                                place_name, partially_str, loop_message
+                                "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
                             ),
                         );
                         // If the moved place was a `&mut` ref, then we can
@@ -1117,7 +1113,7 @@ fn explain_captures(
                                     &format!(
                                         "consider creating a fresh reborrow of {} here",
                                         self.describe_place(moved_place.as_ref())
-                                            .map(|n| format!("`{}`", n))
+                                            .map(|n| format!("`{n}`"))
                                             .unwrap_or_else(|| "the mutable reference".to_string()),
                                     ),
                                     "&mut *",
@@ -1129,12 +1125,47 @@ fn explain_captures(
                         err.span_label(
                             fn_call_span,
                             &format!(
-                                "{} {}moved due to this method call{}",
-                                place_name, partially_str, loop_message
+                                "{place_name} {partially_str}moved due to this method call{loop_message}",
                             ),
                         );
+                        let infcx = tcx.infer_ctxt().build();
+                        let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+                        if let ty::Adt(def, substs) = ty.kind()
+                            && Some(def.did()) == tcx.lang_items().pin_type()
+                            && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
+                            && let self_ty = infcx.replace_bound_vars_with_fresh_vars(
+                                fn_call_span,
+                                LateBoundRegionConversionTime::FnCall,
+                                tcx.fn_sig(method_did).input(0),
+                            )
+                            && infcx.can_eq(self.param_env, ty, self_ty).is_ok()
+                        {
+                            err.span_suggestion_verbose(
+                                fn_call_span.shrink_to_lo(),
+                                "consider reborrowing the `Pin` instead of moving it",
+                                "as_mut().".to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                        if let Some(clone_trait) = tcx.lang_items().clone_trait()
+                            && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
+                            && let o = Obligation::new(
+                                tcx,
+                                ObligationCause::dummy(),
+                                self.param_env,
+                                ty::Binder::dummy(trait_ref),
+                            )
+                            && infcx.predicate_must_hold_modulo_regions(&o)
+                        {
+                            err.span_suggestion_verbose(
+                                fn_call_span.shrink_to_lo(),
+                                "you can `clone` the value and consume it, but this might not be \
+                                 your desired behavior",
+                                "clone().".to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
                     }
-                    let tcx = self.infcx.tcx;
                     // Avoid pointing to the same function in multiple different
                     // error messages.
                     if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
@@ -1169,7 +1200,7 @@ fn explain_captures(
             if move_span != span || !loop_message.is_empty() {
                 err.span_label(
                     move_span,
-                    format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+                    format!("value {partially_str}moved{move_msg} here{loop_message}"),
                 );
             }
             // If the move error occurs due to a loop, don't show
@@ -1177,7 +1208,7 @@ fn explain_captures(
             if loop_message.is_empty() {
                 move_spans.var_span_label(
                     err,
-                    format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
+                    format!("variable {partially_str}moved due to use{}", move_spans.describe()),
                     "moved",
                 );
             }
index 3319a80681fde277dc0fd3f361c2656adfafe6b6..b9cfc7e69610e5d83aed21b6198f245e122757a6 100644 (file)
@@ -180,6 +180,9 @@ pub(crate) fn report_mutability_error(
         // the verbs used in some diagnostic messages.
         let act;
         let acted_on;
+        let mut suggest = true;
+        let mut mut_error = None;
+        let mut count = 1;
 
         let span = match error_access {
             AccessKind::Mutate => {
@@ -194,15 +197,50 @@ pub(crate) fn report_mutability_error(
 
                 let borrow_spans = self.borrow_spans(span, location);
                 let borrow_span = borrow_spans.args_or_use();
-                err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
-                borrow_spans.var_span_label(
-                    &mut err,
-                    format!(
-                        "mutable borrow occurs due to use of {} in closure",
-                        self.describe_any_place(access_place.as_ref()),
-                    ),
-                    "mutable",
-                );
+                match the_place_err {
+                    PlaceRef { local, projection: [] }
+                        if self.body.local_decls[local].can_be_made_mutable() =>
+                    {
+                        let span = self.body.local_decls[local].source_info.span;
+                        mut_error = Some(span);
+                        if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+                            // We've encountered a second (or more) attempt to mutably borrow an
+                            // immutable binding, so the likely problem is with the binding
+                            // declaration, not the use. We collect these in a single diagnostic
+                            // and make the binding the primary span of the error.
+                            err = buffer;
+                            count = c + 1;
+                            if count == 2 {
+                                err.replace_span_with(span, false);
+                                err.span_label(span, "not mutable");
+                            }
+                            suggest = false;
+                        } else {
+                            err = self.cannot_borrow_path_as_mutable_because(
+                                borrow_span,
+                                &item_msg,
+                                &reason,
+                            );
+                        }
+                    }
+                    _ => {
+                        err = self.cannot_borrow_path_as_mutable_because(
+                            borrow_span,
+                            &item_msg,
+                            &reason,
+                        );
+                    }
+                }
+                if suggest {
+                    borrow_spans.var_span_label(
+                        &mut err,
+                        format!(
+                            "mutable borrow occurs due to use of {} in closure",
+                            self.describe_any_place(access_place.as_ref()),
+                        ),
+                        "mutable",
+                    );
+                }
                 borrow_span
             }
         };
@@ -226,7 +264,7 @@ pub(crate) fn report_mutability_error(
                         ProjectionElem::Deref,
                     ],
             } => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
 
                 if let Some(span) = get_mut_span_in_struct_field(
                     self.infcx.tcx,
@@ -252,7 +290,7 @@ pub(crate) fn report_mutability_error(
                     .unwrap_or(false) =>
             {
                 let decl = &self.body.local_decls[local];
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
                 if let Some(mir::Statement {
                     source_info,
                     kind:
@@ -276,7 +314,9 @@ pub(crate) fn report_mutability_error(
                                 pat_span: _,
                             },
                         )))) => {
-                            err.span_note(sp, "the binding is already a mutable borrow");
+                            if suggest {
+                                err.span_note(sp, "the binding is already a mutable borrow");
+                            }
                         }
                         _ => {
                             err.span_note(
@@ -304,20 +344,25 @@ pub(crate) fn report_mutability_error(
                     } else {
                         err.span_help(source_info.span, "try removing `&mut` here");
                     }
-                } else if decl.mutability == Mutability::Not
-                    && !matches!(
+                } else if decl.mutability == Mutability::Not {
+                    if matches!(
                         decl.local_info,
                         Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
                             hir::ImplicitSelfKind::MutRef
-                        ))))
-                    )
-                {
-                    err.span_suggestion_verbose(
-                        decl.source_info.span.shrink_to_lo(),
-                        "consider making the binding mutable",
-                        "mut ",
-                        Applicability::MachineApplicable,
-                    );
+                        ),)))
+                    ) {
+                        err.note(
+                            "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
+                        );
+                        err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
+                    } else {
+                        err.span_suggestion_verbose(
+                            decl.source_info.span.shrink_to_lo(),
+                            "consider making the binding mutable",
+                            "mut ",
+                            Applicability::MachineApplicable,
+                        );
+                    };
                 }
             }
 
@@ -333,16 +378,20 @@ pub(crate) fn report_mutability_error(
                 let local_decl = &self.body.local_decls[local];
                 assert_eq!(local_decl.mutability, Mutability::Not);
 
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
-                err.span_suggestion(
-                    local_decl.source_info.span,
-                    "consider changing this to be mutable",
-                    format!("mut {}", self.local_names[local].unwrap()),
-                    Applicability::MachineApplicable,
-                );
-                let tcx = self.infcx.tcx;
-                if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
-                    self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+                if count < 10 {
+                    err.span_label(span, format!("cannot {act}"));
+                }
+                if suggest {
+                    err.span_suggestion_verbose(
+                        local_decl.source_info.span.shrink_to_lo(),
+                        "consider changing this to be mutable",
+                        "mut ".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                    let tcx = self.infcx.tcx;
+                    if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+                        self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+                    }
                 }
             }
 
@@ -357,7 +406,7 @@ pub(crate) fn report_mutability_error(
 
                 let captured_place = &self.upvars[upvar_index.index()].place;
 
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
 
                 let upvar_hir_id = captured_place.get_root_variable();
 
@@ -397,7 +446,7 @@ pub(crate) fn report_mutability_error(
                     .span_to_snippet(span)
                     .map_or(false, |snippet| snippet.starts_with("&mut ")) =>
             {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
                 err.span_suggestion(
                     span,
                     "try removing `&mut` here",
@@ -409,7 +458,7 @@ pub(crate) fn report_mutability_error(
             PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[local].is_ref_for_guard() =>
             {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
                 err.note(
                     "variables bound in patterns are immutable until the end of the pattern guard",
                 );
@@ -537,7 +586,7 @@ pub(crate) fn report_mutability_error(
                             Some((true, err_help_span, suggested_code)) => {
                                 let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
                                 if !is_trait_sig {
-                                    err.span_suggestion(
+                                    err.span_suggestion_verbose(
                                         err_help_span,
                                         &format!(
                                             "consider changing this to be a mutable {pointer_desc}"
@@ -546,7 +595,7 @@ pub(crate) fn report_mutability_error(
                                         Applicability::MachineApplicable,
                                     );
                                 } else if let Some(x) = local_trait {
-                                    err.span_suggestion(
+                                    err.span_suggestion_verbose(
                                         x,
                                         &format!(
                                             "consider changing that to be a mutable {pointer_desc}"
@@ -569,24 +618,15 @@ pub(crate) fn report_mutability_error(
                         err.span_label(
                             span,
                             format!(
-                                "`{NAME}` is a `{SIGIL}` {DESC}, \
-                                so the data it refers to cannot be {ACTED_ON}",
-                                NAME = name,
-                                SIGIL = pointer_sigil,
-                                DESC = pointer_desc,
-                                ACTED_ON = acted_on
+                                "`{name}` is a `{pointer_sigil}` {pointer_desc}, \
+                                 so the data it refers to cannot be {acted_on}",
                             ),
                         );
                     }
                     _ => {
                         err.span_label(
                             span,
-                            format!(
-                                "cannot {ACT} through `{SIGIL}` {DESC}",
-                                ACT = act,
-                                SIGIL = pointer_sigil,
-                                DESC = pointer_desc
-                            ),
+                            format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"),
                         );
                     }
                 }
@@ -599,19 +639,19 @@ pub(crate) fn report_mutability_error(
             }
 
             PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
 
                 match opt_source {
                     Some(BorrowedContentSource::OverloadedDeref(ty)) => {
                         err.help(&format!(
                             "trait `DerefMut` is required to modify through a dereference, \
-                                but it is not implemented for `{ty}`",
+                             but it is not implemented for `{ty}`",
                         ));
                     }
                     Some(BorrowedContentSource::OverloadedIndex(ty)) => {
                         err.help(&format!(
                             "trait `IndexMut` is required to modify indexed content, \
-                                but it is not implemented for `{ty}`",
+                             but it is not implemented for `{ty}`",
                         ));
                         self.suggest_map_index_mut_alternatives(ty, &mut err, span);
                     }
@@ -620,11 +660,15 @@ pub(crate) fn report_mutability_error(
             }
 
             _ => {
-                err.span_label(span, format!("cannot {ACT}", ACT = act));
+                err.span_label(span, format!("cannot {act}"));
             }
         }
 
-        self.buffer_error(err);
+        if let Some(span) = mut_error {
+            self.buffer_mut_error(span, err, count);
+        } else {
+            self.buffer_error(err);
+        }
     }
 
     fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
@@ -965,7 +1009,7 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &st
         let hir = self.infcx.tcx.hir();
         let closure_id = self.mir_hir_id();
         let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
-        let fn_call_id = hir.get_parent_node(closure_id);
+        let fn_call_id = hir.parent_id(closure_id);
         let node = hir.get(fn_call_id);
         let def_id = hir.enclosing_body_owner(fn_call_id);
         let mut look_at_return = true;
@@ -1168,7 +1212,7 @@ fn suggest_ampmut<'tcx>(
     {
         let lt_name = &src[1..ws_pos];
         let ty = &src[ws_pos..];
-        return (true, highlight_span, format!("&{} mut{}", lt_name, ty));
+        return (true, highlight_span, format!("&{lt_name} mut{ty}"));
     }
 
     let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
@@ -1209,7 +1253,7 @@ fn get_mut_span_in_struct_field<'tcx>(
         // Now we're dealing with the actual struct that we're going to suggest a change to,
         // we can expect a field that is an immutable reference to a type.
         && let hir::Node::Field(field) = node
-        && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
+        && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
     {
         return Some(lt.ident.span.between(ty.span));
     }
index 35c3df768995a0d2907db1cb174122666596a9cc..1eaf0a2f15ce8ffe2468e25a387ec111cd2fe84a 100644 (file)
@@ -209,14 +209,14 @@ pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) {
         let mut diag = if suggested.len() == 1 {
             mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
                 SuggestedConstraint::Outlives(a, bs) => {
-                    let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
-                    format!("add bound `{}: {}`", a, bs.join(" + "))
+                    let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
+                    format!("add bound `{a}: {}`", bs.join(" + "))
                 }
 
                 SuggestedConstraint::Equal(a, b) => {
-                    format!("`{}` and `{}` must be the same: replace one with the other", a, b)
+                    format!("`{a}` and `{b}` must be the same: replace one with the other")
                 }
-                SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
+                SuggestedConstraint::Static(a) => format!("replace `{a}` with `'static`"),
             })
         } else {
             // Create a new diagnostic.
@@ -231,18 +231,16 @@ pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) {
             for constraint in suggested {
                 match constraint {
                     SuggestedConstraint::Outlives(a, bs) => {
-                        let bs: SmallVec<[String; 2]> =
-                            bs.iter().map(|r| format!("{}", r)).collect();
-                        diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
+                        let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
+                        diag.help(&format!("add bound `{a}: {}`", bs.join(" + ")));
                     }
                     SuggestedConstraint::Equal(a, b) => {
                         diag.help(&format!(
-                            "`{}` and `{}` must be the same: replace one with the other",
-                            a, b
+                            "`{a}` and `{b}` must be the same: replace one with the other",
                         ));
                     }
                     SuggestedConstraint::Static(a) => {
-                        diag.help(&format!("replace `{}` with `'static`", a));
+                        diag.help(&format!("replace `{a}` with `'static`"));
                     }
                 }
             }
index bcc8afbfd952d15763d32cd6239c5c129ee8f35b..e8a4d1c37c1877296151a84dd9e3cd5513716b2b 100644 (file)
@@ -4,9 +4,9 @@
 
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, Item, ItemKind, Node};
 use rustc_infer::infer::{
     error_reporting::nice_region_error::{
         self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
@@ -192,6 +192,8 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
         // buffered in the `MirBorrowckCtxt`.
 
         let mut outlives_suggestion = OutlivesSuggestionBuilder::default();
+        let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
+            None;
 
         for nll_error in nll_errors.into_iter() {
             match nll_error {
@@ -234,13 +236,19 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                     let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
                     let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
                     let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
-                    self.buffer_error(unexpected_hidden_region_diagnostic(
+                    let mut diag = unexpected_hidden_region_diagnostic(
                         self.infcx.tcx,
                         span,
                         named_ty,
                         named_region,
                         named_key,
-                    ));
+                    );
+                    if last_unexpected_hidden_region != Some((span, named_ty, named_key)) {
+                        self.buffer_error(diag);
+                        last_unexpected_hidden_region = Some((span, named_ty, named_key));
+                    } else {
+                        diag.delay_as_bug();
+                    }
                 }
 
                 RegionErrorKind::BoundUniversalRegionError {
@@ -291,71 +299,6 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
         outlives_suggestion.add_suggestion(self);
     }
 
-    fn get_impl_ident_and_self_ty_from_trait(
-        &self,
-        def_id: DefId,
-        trait_objects: &FxIndexSet<DefId>,
-    ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        let tcx = self.infcx.tcx;
-        match tcx.hir().get_if_local(def_id) {
-            Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
-                {
-                    Some(Node::Item(Item {
-                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                        ..
-                    })) => Some((impl_item.ident, self_ty)),
-                    _ => None,
-                }
-            }
-            Some(Node::TraitItem(trait_item)) => {
-                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did.def_id) {
-                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
-                        // The method being called is defined in the `trait`, but the `'static`
-                        // obligation comes from the `impl`. Find that `impl` so that we can point
-                        // at it in the suggestion.
-                        let trait_did = trait_did.to_def_id();
-                        match tcx
-                            .hir()
-                            .trait_impls(trait_did)
-                            .iter()
-                            .filter_map(|&impl_did| {
-                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
-                                    Some(Node::Item(Item {
-                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                                        ..
-                                    })) if trait_objects.iter().all(|did| {
-                                        // FIXME: we should check `self_ty` against the receiver
-                                        // type in the `UnifyReceiver` context, but for now, use
-                                        // this imperfect proxy. This will fail if there are
-                                        // multiple `impl`s for the same trait like
-                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
-                                        // In that case, only the first one will get suggestions.
-                                        let mut traits = vec![];
-                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
-                                        hir_v.visit_ty(self_ty);
-                                        !traits.is_empty()
-                                    }) =>
-                                    {
-                                        Some(self_ty)
-                                    }
-                                    _ => None,
-                                }
-                            })
-                            .next()
-                        {
-                            Some(self_ty) => Some((trait_item.ident, self_ty)),
-                            _ => None,
-                        }
-                    }
-                    _ => None,
-                }
-            }
-            _ => None,
-        }
-    }
-
     /// Report an error because the universal region `fr` was required to outlive
     /// `outlived_fr` but it is not known to do so. For example:
     ///
@@ -479,7 +422,7 @@ pub(crate) fn report_region_error(
                         );
                         (desc, note)
                     }
-                    _ => panic!("Unexpected type {:?}", ty),
+                    _ => panic!("Unexpected type {ty:?}"),
                 };
                 diag.note(&format!("requirement occurs because of {desc}",));
                 diag.note(&note);
@@ -782,10 +725,10 @@ fn add_static_impl_trait_suggestion(
             let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime };
 
             let arg = match param.param.pat.simple_ident() {
-                Some(simple_ident) => format!("argument `{}`", simple_ident),
+                Some(simple_ident) => format!("argument `{simple_ident}`"),
                 None => "the argument".to_string(),
             };
-            let captures = format!("captures data from {}", arg);
+            let captures = format!("captures data from {arg}");
 
             return nice_region_error::suggest_new_region_bound(
                 self.infcx.tcx,
@@ -795,6 +738,7 @@ fn add_static_impl_trait_suggestion(
                 Some(arg),
                 captures,
                 Some((param.param_ty_span, param.param_ty.to_string())),
+                self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id),
             );
         }
     }
@@ -850,7 +794,7 @@ fn maybe_suggest_constrain_dyn_trait_impl(
         visitor.visit_ty(param.param_ty);
 
         let Some((ident, self_ty)) =
-            self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+            NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &visitor.0) else { return; };
 
         self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
     }
index 171e62d91e136463dfd600eb3dc9b51977b6ca59..9233287cf3a75fde48da92820c9c4d52bed5e132 100644 (file)
@@ -200,9 +200,9 @@ pub(crate) fn mir_hir_id(&self) -> hir::HirId {
     /// increment the counter.
     ///
     /// This is _not_ idempotent. Call `give_region_a_name` when possible.
-    fn synthesize_region_name(&self) -> Symbol {
+    pub(crate) fn synthesize_region_name(&self) -> Symbol {
         let c = self.next_region_name.replace_with(|counter| *counter + 1);
-        Symbol::intern(&format!("'{:?}", c))
+        Symbol::intern(&format!("'{c:?}"))
     }
 
     /// Maps from an internal MIR region vid to something that we can
@@ -493,10 +493,7 @@ fn highlight_if_we_can_match_hir_ty(
                 //
                 //     &
                 //     - let's call the lifetime of this reference `'1`
-                (
-                    ty::Ref(region, referent_ty, _),
-                    hir::TyKind::Rptr(_lifetime, referent_hir_ty),
-                ) => {
+                (ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => {
                     if region.to_region_vid() == needle_fr {
                         // Just grab the first character, the `&`.
                         let source_map = self.infcx.tcx.sess.source_map();
@@ -622,7 +619,7 @@ fn try_match_adt_and_generic_args<'hir>(
                     // programs, so we need to use delay_span_bug here. See #82126.
                     self.infcx.tcx.sess.delay_span_bug(
                         hir_arg.span(),
-                        &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg),
+                        &format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
                     );
                 }
             }
@@ -786,8 +783,7 @@ fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::
         } else {
             span_bug!(
                 hir_ty.span,
-                "bounds from lowered return type of async fn did not match expected format: {:?}",
-                opaque_ty
+                "bounds from lowered return type of async fn did not match expected format: {opaque_ty:?}",
             );
         }
     }
index b385f95b67c6f992a12841c02b77b7bed01b8f35..ada3310d8071b776215d5ce4c5c5d037d353df93 100644 (file)
@@ -18,7 +18,7 @@ pub(crate) fn get_var_name_and_span_for_region(
         upvars: &[Upvar<'tcx>],
         fr: RegionVid,
     ) -> Option<(Option<Symbol>, Span)> {
-        debug!("get_var_name_and_span_for_region(fr={:?})", fr);
+        debug!("get_var_name_and_span_for_region(fr={fr:?})");
         assert!(self.universal_regions().is_universal_region(fr));
 
         debug!("get_var_name_and_span_for_region: attempting upvar");
@@ -44,10 +44,10 @@ pub(crate) fn get_upvar_index_for_region(
     ) -> Option<usize> {
         let upvar_index =
             self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
-                debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
+                debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}");
                 tcx.any_free_region_meets(&upvar_ty, |r| {
                     let r = r.to_region_vid();
-                    debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
+                    debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}");
                     r == fr
                 })
             })?;
@@ -55,8 +55,7 @@ pub(crate) fn get_upvar_index_for_region(
         let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index);
 
         debug!(
-            "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
-            fr, upvar_index, upvar_ty,
+            "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}",
         );
 
         Some(upvar_index)
@@ -71,13 +70,12 @@ pub(crate) fn get_upvar_name_and_span_for_region(
         upvar_index: usize,
     ) -> (Symbol, Span) {
         let upvar_hir_id = upvars[upvar_index].place.get_root_variable();
-        debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
+        debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}");
 
         let upvar_name = tcx.hir().name(upvar_hir_id);
         let upvar_span = tcx.hir().span(upvar_hir_id);
         debug!(
-            "get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
-            upvar_name, upvar_span
+            "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}",
         );
 
         (upvar_name, upvar_span)
@@ -97,15 +95,13 @@ pub(crate) fn get_argument_index_for_region(
         let argument_index =
             self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position(
                 |arg_ty| {
-                    debug!("get_argument_index_for_region: arg_ty = {:?}", arg_ty);
+                    debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}");
                     tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
                 },
             )?;
 
         debug!(
-            "get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
-            fr,
-            argument_index,
+            "get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}",
             self.universal_regions().unnormalized_input_tys[argument_index],
         );
 
@@ -122,13 +118,12 @@ pub(crate) fn get_argument_name_and_span_for_region(
     ) -> (Option<Symbol>, Span) {
         let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs();
         let argument_local = Local::new(implicit_inputs + argument_index + 1);
-        debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
+        debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}");
 
         let argument_name = local_names[argument_local];
         let argument_span = body.local_decls[argument_local].source_info.span;
         debug!(
-            "get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
-            argument_name, argument_span
+            "get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}",
         );
 
         (argument_name, argument_span)
index 51ed27c167d3844971e445036bb0a4584524e210..02ffb51fbb7e3a3fb440a497e558702fefc5ba41 100644 (file)
@@ -192,7 +192,7 @@ fn write_row(
 ) -> Result<(), Box<dyn Error>> {
     for (index, c) in columns.iter().enumerate() {
         let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
-        write!(out, "{:?}{}", c.to_string(location_table), tail)?;
+        write!(out, "{:?}{tail}", c.to_string(location_table))?;
     }
     Ok(())
 }
index 168b798788b4c747c7fad8e4db5337b5f36fceaf..278ffed07477b5b3bdf8224a7b3c79c89b2b9ace 100644 (file)
@@ -863,7 +863,6 @@ enum WriteKind {
 /// local place can be mutated.
 //
 // FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
-// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`.
 // - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
 //   `is_declared_mutable()`.
 // - Take flow state into consideration in `is_assignable()` for local variables.
@@ -1132,20 +1131,6 @@ fn mutate_place(
         // Write of P[i] or *P requires P init'd.
         self.check_if_assigned_path_is_moved(location, place_span, flow_state);
 
-        // Special case: you can assign an immutable local variable
-        // (e.g., `x = ...`) so long as it has never been initialized
-        // before (at this point in the flow).
-        if let Some(local) = place_span.0.as_local() {
-            if let Mutability::Not = self.body.local_decls[local].mutability {
-                // check for reassignments to immutable local variables
-                self.check_if_reassignment_to_immutable_state(
-                    location, local, place_span, flow_state,
-                );
-                return;
-            }
-        }
-
-        // Otherwise, use the normal access permission rules.
         self.access_place(
             location,
             place_span,
@@ -1554,24 +1539,6 @@ fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flo
         }
     }
 
-    fn check_if_reassignment_to_immutable_state(
-        &mut self,
-        location: Location,
-        local: Local,
-        place_span: (Place<'tcx>, Span),
-        flow_state: &Flows<'cx, 'tcx>,
-    ) {
-        debug!("check_if_reassignment_to_immutable_state({:?})", local);
-
-        // Check if any of the initializations of `local` have happened yet:
-        if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
-            // And, if so, report an error.
-            let init = &self.move_data.inits[init_index];
-            let span = init.span(&self.body);
-            self.report_illegal_reassignment(location, place_span, span, place_span.0);
-        }
-    }
-
     fn check_if_full_path_is_moved(
         &mut self,
         location: Location,
@@ -2037,12 +2004,19 @@ fn check_access_permissions(
         // partial initialization, do not complain about mutability
         // errors except for actual mutation (as opposed to an attempt
         // to do a partial initialization).
-        let previously_initialized =
-            self.is_local_ever_initialized(place.local, flow_state).is_some();
+        let previously_initialized = self.is_local_ever_initialized(place.local, flow_state);
 
         // at this point, we have set up the error reporting state.
-        if previously_initialized {
-            self.report_mutability_error(place, span, the_place_err, error_access, location);
+        if let Some(init_index) = previously_initialized {
+            if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
+                // If this is a mutate access to an immutable local variable with no projections
+                // report the error as an illegal reassignment
+                let init = &self.move_data.inits[init_index];
+                let assigned_span = init.span(&self.body);
+                self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+            } else {
+                self.report_mutability_error(place, span, the_place_err, error_access, location)
+            }
             true
         } else {
             false
@@ -2270,6 +2244,7 @@ pub struct BorrowckErrors<'tcx> {
         /// same primary span come out in a consistent order.
         buffered_move_errors:
             BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+        buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
         /// Diagnostics to be reported buffer.
         buffered: Vec<Diagnostic>,
         /// Set to Some if we emit an error during borrowck
@@ -2281,6 +2256,7 @@ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
             BorrowckErrors {
                 tcx,
                 buffered_move_errors: BTreeMap::new(),
+                buffered_mut_errors: Default::default(),
                 buffered: Default::default(),
                 tainted_by_errors: None,
             }
@@ -2331,12 +2307,34 @@ pub fn buffer_move_error(
             }
         }
 
+        pub fn get_buffered_mut_error(
+            &mut self,
+            span: Span,
+        ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+            self.errors.buffered_mut_errors.remove(&span)
+        }
+
+        pub fn buffer_mut_error(
+            &mut self,
+            span: Span,
+            t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+            count: usize,
+        ) {
+            self.errors.buffered_mut_errors.insert(span, (t, count));
+        }
+
         pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
             // Buffer any move errors that we collected and de-duplicated.
             for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
                 // We have already set tainted for this error, so just buffer it.
                 diag.buffer(&mut self.errors.buffered);
             }
+            for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+                if count > 10 {
+                    diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+                }
+                diag.buffer(&mut self.errors.buffered);
+            }
 
             if !self.errors.buffered.is_empty() {
                 self.errors.buffered.sort_by_key(|diag| diag.sort_span);
index 3617bf58be9dd48dd17c18c8738eb566024e18c9..02222c0a03cb350f9dcfdebc2b963db3f1edfcd5 100644 (file)
@@ -1,13 +1,13 @@
 use std::fmt;
 
-use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::traits::query::NoSolution;
+use rustc_infer::infer::{canonical::Canonical, InferOk};
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
-use rustc_trait_selection::traits::query::Fallible;
+use rustc_trait_selection::traits::query::{Fallible, NoSolution};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 
 use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
 
@@ -177,4 +177,74 @@ pub(super) fn normalize_with_category<T>(
             value
         })
     }
+
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn ascribe_user_type(
+        &mut self,
+        mir_ty: Ty<'tcx>,
+        user_ty: ty::UserType<'tcx>,
+        span: Span,
+    ) {
+        // FIXME: Ideally MIR types are normalized, but this is not always true.
+        let mir_ty = self.normalize(mir_ty, Locations::All(span));
+
+        self.fully_perform_op(
+            Locations::All(span),
+            ConstraintCategory::Boring,
+            self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
+        )
+        .unwrap_or_else(|err| {
+            span_mirbug!(
+                self,
+                span,
+                "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
+            );
+        });
+    }
+
+    /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
+    ///
+    /// FIXME(#104478, #104477): This is a hack for backward-compatibility.
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn ascribe_user_type_skip_wf(
+        &mut self,
+        mir_ty: Ty<'tcx>,
+        user_ty: ty::UserType<'tcx>,
+        span: Span,
+    ) {
+        let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
+
+        // A fast path for a common case with closure input/output types.
+        if let ty::Infer(_) = user_ty.kind() {
+            self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
+                .unwrap();
+            return;
+        }
+
+        let mir_ty = self.normalize(mir_ty, Locations::All(span));
+        let cause = ObligationCause::dummy_with_span(span);
+        let param_env = self.param_env;
+        let op = |infcx: &'_ _| {
+            let ocx = ObligationCtxt::new_in_snapshot(infcx);
+            let user_ty = ocx.normalize(&cause, param_env, user_ty);
+            ocx.eq(&cause, param_env, user_ty, mir_ty)?;
+            if !ocx.select_all_or_error().is_empty() {
+                return Err(NoSolution);
+            }
+            Ok(InferOk { value: (), obligations: vec![] })
+        };
+
+        self.fully_perform_op(
+            Locations::All(span),
+            ConstraintCategory::Boring,
+            type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
+        )
+        .unwrap_or_else(|err| {
+            span_mirbug!(
+                self,
+                span,
+                "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
+            );
+        });
+    }
 }
index 8fa43f8528cca2a6b0f7b1b1e96c633ae7761adc..fa9ea769a14f79607e86c7d69dafbec2216b5c1a 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_index::vec::Idx;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::*;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 
 use crate::universal_regions::UniversalRegions;
 use super::{Locations, TypeChecker};
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+    /// Check explicit closure signature annotation,
+    /// e.g., `|x: FxHashMap<_, &'static u32>| ...`.
+    #[instrument(skip(self, body), level = "debug")]
+    pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
+        let mir_def_id = body.source.def_id().expect_local();
+        if !self.tcx().is_closure(mir_def_id.to_def_id()) {
+            return;
+        }
+        let Some(user_provided_poly_sig) =
+            self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
+        else {
+            return;
+        };
+
+        // Instantiate the canonicalized variables from user-provided signature
+        // (e.g., the `_` in the code above) with fresh variables.
+        // Then replace the bound items in the fn sig with fresh variables,
+        // 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(
+            body.span,
+            LateBoundRegionConversionTime::FnCall,
+            user_provided_sig,
+        );
+
+        for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip(
+            // In MIR, closure args begin with an implicit `self`. Skip it!
+            body.args_iter().skip(1).map(|local| &body.local_decls[local]),
+        ) {
+            self.ascribe_user_type_skip_wf(
+                arg_decl.ty,
+                ty::UserType::Ty(user_ty),
+                arg_decl.source_info.span,
+            );
+        }
+
+        // If the user explicitly annotated the output type, enforce it.
+        let output_decl = &body.local_decls[RETURN_PLACE];
+        self.ascribe_user_type_skip_wf(
+            output_decl.ty,
+            ty::UserType::Ty(user_provided_sig.output()),
+            output_decl.source_info.span,
+        );
+    }
+
     #[instrument(skip(self, body, universal_regions), level = "debug")]
     pub(super) fn equate_inputs_and_outputs(
         &mut self,
@@ -31,39 +77,6 @@ pub(super) fn equate_inputs_and_outputs(
         debug!(?normalized_output_ty);
         debug!(?normalized_input_tys);
 
-        let mir_def_id = body.source.def_id().expect_local();
-
-        // If the user explicitly annotated the input types, extract
-        // those.
-        //
-        // e.g., `|x: FxHashMap<_, &'static u32>| ...`
-        let user_provided_sig = if !self.tcx().is_closure(mir_def_id.to_def_id()) {
-            None
-        } else {
-            let typeck_results = self.tcx().typeck(mir_def_id);
-
-            typeck_results.user_provided_sigs.get(&mir_def_id).map(|user_provided_poly_sig| {
-                // Instantiate the canonicalized variables from
-                // user-provided signature (e.g., the `_` in the code
-                // above) with fresh variables.
-                let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
-                    body.span,
-                    &user_provided_poly_sig,
-                );
-
-                // Replace the bound items in the fn sig with fresh
-                // variables, so that they represent the view from
-                // "inside" the closure.
-                self.infcx.replace_bound_vars_with_fresh_vars(
-                    body.span,
-                    LateBoundRegionConversionTime::FnCall,
-                    poly_sig,
-                )
-            })
-        };
-
-        debug!(?normalized_input_tys, ?body.local_decls);
-
         // Equate expected input tys with those in the MIR.
         for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
             if argument_index + 1 >= body.local_decls.len() {
@@ -86,28 +99,6 @@ pub(super) fn equate_inputs_and_outputs(
             );
         }
 
-        if let Some(user_provided_sig) = user_provided_sig {
-            for (argument_index, &user_provided_input_ty) in
-                user_provided_sig.inputs().iter().enumerate()
-            {
-                // In MIR, closures begin an implicit `self`, so
-                // argument N is stored in local N+2.
-                let local = Local::new(argument_index + 2);
-                let mir_input_ty = body.local_decls[local].ty;
-                let mir_input_span = body.local_decls[local].source_info.span;
-
-                // If the user explicitly annotated the input types, enforce those.
-                let user_provided_input_ty =
-                    self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
-
-                self.equate_normalized_input_or_output(
-                    user_provided_input_ty,
-                    mir_input_ty,
-                    mir_input_span,
-                );
-            }
-        }
-
         debug!(
             "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
             body.yield_ty(),
@@ -153,29 +144,6 @@ pub(super) fn equate_inputs_and_outputs(
                 terr
             );
         };
-
-        // If the user explicitly annotated the output types, enforce those.
-        // Note that this only happens for closures.
-        if let Some(user_provided_sig) = user_provided_sig {
-            let user_provided_output_ty = user_provided_sig.output();
-            let user_provided_output_ty =
-                self.normalize(user_provided_output_ty, Locations::All(output_span));
-            if let Err(err) = self.eq_types(
-                user_provided_output_ty,
-                mir_output_ty,
-                Locations::All(output_span),
-                ConstraintCategory::BoringNoLocation,
-            ) {
-                span_mirbug!(
-                    self,
-                    Location::START,
-                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
-                    mir_output_ty,
-                    user_provided_output_ty,
-                    err
-                );
-            }
-        }
     }
 
     #[instrument(skip(self), level = "debug")]
index 247607ff29e20717196020ee862ae279fbb268b6..8778a19eeda1bf37080e516c9816889ff9e3c74e 100644 (file)
@@ -38,7 +38,6 @@
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -197,6 +196,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
     }
 
     checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
+    checker.check_signature_annotation(&body);
+
     liveness::generate(
         &mut checker,
         body,
@@ -391,23 +392,14 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
                         check_err(self, promoted_body, ty, promoted_ty);
                     }
                 } else {
-                    if let Err(terr) = self.cx.fully_perform_op(
-                        locations,
-                        ConstraintCategory::Boring,
-                        self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
-                            constant.literal.ty(),
+                    self.cx.ascribe_user_type(
+                        constant.literal.ty(),
+                        UserType::TypeOf(
                             uv.def.did,
                             UserSubsts { substs: uv.substs, user_self_ty: None },
-                        )),
-                    ) {
-                        span_mirbug!(
-                            self,
-                            constant,
-                            "bad constant type {:?} ({:?})",
-                            constant,
-                            terr
-                        );
-                    }
+                        ),
+                        locations.span(&self.cx.body),
+                    );
                 }
             } else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
                 let unnormalized_ty = tcx.type_of(static_def_id);
@@ -1041,58 +1033,8 @@ fn check_user_type_annotations(&mut self) {
         debug!(?self.user_type_annotations);
         for user_annotation in self.user_type_annotations {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
-            let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
             let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
-            debug!(?annotation);
-            match annotation {
-                UserType::Ty(mut ty) => {
-                    ty = self.normalize(ty, Locations::All(span));
-
-                    if let Err(terr) = self.eq_types(
-                        ty,
-                        inferred_ty,
-                        Locations::All(span),
-                        ConstraintCategory::BoringNoLocation,
-                    ) {
-                        span_mirbug!(
-                            self,
-                            user_annotation,
-                            "bad user type ({:?} = {:?}): {:?}",
-                            ty,
-                            inferred_ty,
-                            terr
-                        );
-                    }
-
-                    self.prove_predicate(
-                        ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())),
-                        Locations::All(span),
-                        ConstraintCategory::TypeAnnotation,
-                    );
-                }
-                UserType::TypeOf(def_id, user_substs) => {
-                    if let Err(terr) = self.fully_perform_op(
-                        Locations::All(span),
-                        ConstraintCategory::BoringNoLocation,
-                        self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
-                            inferred_ty,
-                            def_id,
-                            user_substs,
-                        )),
-                    ) {
-                        span_mirbug!(
-                            self,
-                            user_annotation,
-                            "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}",
-                            inferred_ty,
-                            def_id,
-                            user_substs,
-                            self.tcx().type_of(def_id),
-                            terr,
-                        );
-                    }
-                }
-            }
+            self.ascribe_user_type(inferred_ty, annotation, span);
         }
     }
 
index 544d971b27a5d9473a375d0c2b692a16912fac6a..5b1b7e6804c86d7235d0597e074901dba8fa0b37 100644 (file)
@@ -117,8 +117,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         // `let names: &'static _ = &["field1", "field2"];`
         let names_let = if is_struct {
             let lt_static = Some(cx.lifetime_static(span));
-            let ty_static_ref =
-                cx.ty_rptr(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
+            let ty_static_ref = cx.ty_ref(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
             Some(cx.stmt_let_ty(
                 span,
                 false,
@@ -138,13 +137,13 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         );
         let ty_slice = cx.ty(
             span,
-            ast::TyKind::Slice(cx.ty_rptr(span, ty_dyn_debug, None, ast::Mutability::Not)),
+            ast::TyKind::Slice(cx.ty_ref(span, ty_dyn_debug, None, ast::Mutability::Not)),
         );
         let values_let = cx.stmt_let_ty(
             span,
             false,
             Ident::new(sym::values, span),
-            Some(cx.ty_rptr(span, ty_slice, None, ast::Mutability::Not)),
+            Some(cx.ty_ref(span, ty_slice, None, ast::Mutability::Not)),
             cx.expr_array_ref(span, value_exprs),
         );
 
index eaa4881906a8e3aed446cec6b99657d64972d02f..c6f5f5d080706be7d41c7c52d8840edf6b545b42 100644 (file)
@@ -97,7 +97,7 @@ pub fn to_ty(
         match self {
             Ref(ty, mutbl) => {
                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
-                cx.ty_rptr(span, raw_ty, None, *mutbl)
+                cx.ty_ref(span, raw_ty, None, *mutbl)
             }
             Path(p) => p.to_ty(cx, span, self_ty, self_generics),
             Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
index a7283ea601b19e4c20a846beb76663562001da0f..84d06b69a9d976c3d7c260dfe723693139dfe80b 100644 (file)
@@ -30,7 +30,7 @@ pub fn expand_option_env<'cx>(
                 sp,
                 true,
                 cx.std_path(&[sym::option, sym::Option, sym::None]),
-                vec![GenericArg::Type(cx.ty_rptr(
+                vec![GenericArg::Type(cx.ty_ref(
                     sp,
                     cx.ty_ident(sp, Ident::new(sym::str, sp)),
                     Some(lt),
index 63bc0d552c11e7e24e17bbb45ff095590fd1f18b..b2b7b9d75bd37163e9ac20a305ba9e19ac9366ef 100644 (file)
@@ -638,7 +638,7 @@ macro_rules! check_foreign {
                 if show_doc_note {
                     diag.note(concat!(
                         stringify!($kind),
-                        " formatting not supported; see the documentation for `std::fmt`",
+                        " formatting is not supported; see the documentation for `std::fmt`",
                     ));
                 }
                 if suggestions.len() > 0 {
index b88de224675379a24f1f78e50c9ea9f0fc7f60a1..21c8caa658f24422567d56bf8474f5b9c6104d22 100644 (file)
@@ -349,7 +349,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
         .item_static(
             span,
             Ident::new(sym::_DECLS, span),
-            cx.ty_rptr(
+            cx.ty_ref(
                 span,
                 cx.ty(
                     span,
index effb2de4827518c08360bed61995f5ffe3c86a58..a92242b2615c1f66b1cfb438c61a0bbf48ad0e97 100644 (file)
@@ -1244,7 +1244,7 @@ fn call(
     ) -> RValue<'gcc> {
         // FIXME(antoyo): remove when having a proper API.
         let gcc_func = unsafe { std::mem::transmute(func) };
-        let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+        let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
             self.function_call(func, args, funclet)
         }
         else {
index 837708aeb0ea9a42aa4a36aced6b7a19a40bddd3..4424b31c0542c65777d80571ebc85cafbdd1c925 100644 (file)
@@ -253,7 +253,7 @@ pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>,
 
     pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
         let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
-        debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+        debug_assert!(self.functions.borrow().values().any(|value| *value == function),
             "{:?} ({:?}) is not a function", value, value.get_type());
         function
     }
index a6fd2a7de6bd04eb544c7d10f78111d8de5938e2..546540dfd76232ad2b6d50887e1b9304d1f9e63d 100644 (file)
@@ -34,13 +34,6 @@ fn apply_attrs_to_callsite(
     );
 }
 
-fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
-    // LLVM prior to version 12 had known miscompiles in the presence of
-    // noalias attributes (see #54878), but we don't support earlier
-    // versions at all anymore. We now enable mutable noalias by default.
-    cx.tcx.sess.opts.unstable_opts.mutable_noalias.unwrap_or(true)
-}
-
 const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
     [(ArgAttribute::InReg, llvm::AttributeKind::InReg)];
 
@@ -88,9 +81,6 @@ fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
                 attrs.push(llattr.create_attr(cx.llcx));
             }
         }
-        if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
-            attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx));
-        }
     } else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
         // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
         // memory sanitizer's behavior.
index 1ce48f82e1c9b739bf26fd800d132544706f72d7..680d810f78eb9b4121e98955f6cbad23629f52a3 100644 (file)
@@ -8,8 +8,8 @@
 use crate::value::Value;
 
 use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
-use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
+use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
 use rustc_codegen_ssa::mir::operand::OperandRef;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
@@ -284,15 +284,11 @@ fn codegen_intrinsic_call(
                         _ => bug!(),
                     },
                     None => {
-                        span_invalid_monomorphization_error(
-                            tcx.sess,
+                        tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType {
                             span,
-                            &format!(
-                                "invalid monomorphization of `{}` intrinsic: \
-                                      expected basic integer type, found `{}`",
-                                name, ty
-                            ),
-                        );
+                            name,
+                            ty,
+                        });
                         return;
                     }
                 }
@@ -838,40 +834,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     llret_ty: &'ll Type,
     span: Span,
 ) -> Result<&'ll Value, ()> {
-    // macros for error handling:
-    #[allow(unused_macro_rules)]
-    macro_rules! emit_error {
-        ($msg: tt) => {
-            emit_error!($msg, )
-        };
-        ($msg: tt, $($fmt: tt)*) => {
-            span_invalid_monomorphization_error(
-                bx.sess(), span,
-                &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
-                         name, $($fmt)*));
-        }
-    }
-
     macro_rules! return_error {
-        ($($fmt: tt)*) => {
-            {
-                emit_error!($($fmt)*);
-                return Err(());
-            }
-        }
+        ($diag: expr) => {{
+            bx.sess().emit_err($diag);
+            return Err(());
+        }};
     }
 
     macro_rules! require {
-        ($cond: expr, $($fmt: tt)*) => {
+        ($cond: expr, $diag: expr) => {
             if !$cond {
-                return_error!($($fmt)*);
+                return_error!($diag);
             }
         };
     }
 
     macro_rules! require_simd {
-        ($ty: expr, $position: expr) => {
-            require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+        ($ty: expr, $diag: expr) => {
+            require!($ty.is_simd(), $diag)
         };
     }
 
@@ -881,7 +861,11 @@ macro_rules! require_simd {
     let arg_tys = sig.inputs();
 
     if name == sym::simd_select_bitmask {
-        require_simd!(arg_tys[1], "argument");
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
+        );
+
         let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
 
         let expected_int_bits = (len.max(8) - 1).next_power_of_two();
@@ -902,12 +886,13 @@ macro_rules! require_simd {
                 let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
                 bx.load(int_ty, ptr, Align::ONE)
             }
-            _ => return_error!(
-                "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
+            _ => return_error!(InvalidMonomorphization::InvalidBitmask {
+                span,
+                name,
                 mask_ty,
                 expected_int_bits,
                 expected_bytes
-            ),
+            }),
         };
 
         let i1 = bx.type_i1();
@@ -919,7 +904,7 @@ macro_rules! require_simd {
     }
 
     // every intrinsic below takes a SIMD vector as its first argument
-    require_simd!(arg_tys[0], "input");
+    require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
     let in_ty = arg_tys[0];
 
     let comparison = match name {
@@ -934,23 +919,24 @@ macro_rules! require_simd {
 
     let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
     if let Some(cmp_op) = comparison {
-        require_simd!(ret_ty, "return");
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+
         require!(
             in_len == out_len,
-            "expected return type with length {} (same as input type `{}`), \
-             found `{}` with length {}",
-            in_len,
-            in_ty,
-            ret_ty,
-            out_len
+            InvalidMonomorphization::ReturnLengthInputType {
+                span,
+                name,
+                in_len,
+                in_ty,
+                ret_ty,
+                out_len
+            }
         );
         require!(
             bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
-            "expected return type with integer elements, found `{}` with non-integer `{}`",
-            ret_ty,
-            out_ty
+            InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
         );
 
         return Ok(compare_simd_types(
@@ -975,10 +961,11 @@ macro_rules! require_simd {
                         span_bug!(span, "could not evaluate shuffle index array length")
                     })
                 }
-                _ => return_error!(
-                    "simd_shuffle index must be an array of `u32`, got `{}`",
-                    args[2].layout.ty
-                ),
+                _ => return_error!(InvalidMonomorphization::SimdShuffle {
+                    span,
+                    name,
+                    ty: args[2].layout.ty
+                }),
             }
         } else {
             stripped.parse().unwrap_or_else(|_| {
@@ -986,23 +973,15 @@ macro_rules! require_simd {
             })
         };
 
-        require_simd!(ret_ty, "return");
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             out_len == n,
-            "expected return type of length {}, found `{}` with length {}",
-            n,
-            ret_ty,
-            out_len
+            InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
         );
         require!(
             in_elem == out_ty,
-            "expected return element type `{}` (element of input `{}`), \
-             found `{}` with element type `{}`",
-            in_elem,
-            in_ty,
-            ret_ty,
-            out_ty
+            InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
         );
 
         let total_len = u128::from(in_len) * 2;
@@ -1015,15 +994,20 @@ macro_rules! require_simd {
                 let val = bx.const_get_elt(vector, i as u64);
                 match bx.const_to_opt_u128(val, true) {
                     None => {
-                        emit_error!("shuffle index #{} is not a constant", arg_idx);
+                        bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexNotConstant {
+                            span,
+                            name,
+                            arg_idx,
+                        });
                         None
                     }
                     Some(idx) if idx >= total_len => {
-                        emit_error!(
-                            "shuffle index #{} is out of bounds (limit {})",
+                        bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
+                            span,
+                            name,
                             arg_idx,
-                            total_len
-                        );
+                            total_len,
+                        });
                         None
                     }
                     Some(idx) => Some(bx.const_i32(idx as i32)),
@@ -1044,10 +1028,13 @@ macro_rules! require_simd {
     if name == sym::simd_insert {
         require!(
             in_elem == arg_tys[2],
-            "expected inserted type `{}` (element of input `{}`), found `{}`",
-            in_elem,
-            in_ty,
-            arg_tys[2]
+            InvalidMonomorphization::InsertedType {
+                span,
+                name,
+                in_elem,
+                in_ty,
+                out_ty: arg_tys[2]
+            }
         );
         return Ok(bx.insert_element(
             args[0].immediate(),
@@ -1058,10 +1045,7 @@ macro_rules! require_simd {
     if name == sym::simd_extract {
         require!(
             ret_ty == in_elem,
-            "expected return type `{}` (element of input `{}`), found `{}`",
-            in_elem,
-            in_ty,
-            ret_ty
+            InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
         );
         return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
     }
@@ -1069,17 +1053,18 @@ macro_rules! require_simd {
     if name == sym::simd_select {
         let m_elem_ty = in_elem;
         let m_len = in_len;
-        require_simd!(arg_tys[1], "argument");
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
+        );
         let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         require!(
             m_len == v_len,
-            "mismatched lengths: mask length `{}` != other vector length `{}`",
-            m_len,
-            v_len
+            InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
         );
         match m_elem_ty.kind() {
             ty::Int(_) => {}
-            _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty),
+            _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
         }
         // truncate the mask to a vector of i1s
         let i1 = bx.type_i1();
@@ -1111,11 +1096,12 @@ macro_rules! require_simd {
                 args[0].immediate(),
                 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
             ),
-            _ => return_error!(
-                "vector argument `{}`'s element type `{}`, expected integer element type",
+            _ => return_error!(InvalidMonomorphization::VectorArgument {
+                span,
+                name,
                 in_ty,
                 in_elem
-            ),
+            }),
         };
 
         // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
@@ -1150,12 +1136,13 @@ macro_rules! require_simd {
                 let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
                 return Ok(bx.load(array_ty, ptr, Align::ONE));
             }
-            _ => return_error!(
-                "cannot return `{}`, expected `u{}` or `[u8; {}]`",
+            _ => return_error!(InvalidMonomorphization::CannotReturn {
+                span,
+                name,
                 ret_ty,
                 expected_int_bits,
                 expected_bytes
-            ),
+            }),
         }
     }
 
@@ -1168,25 +1155,11 @@ fn simd_simple_float_intrinsic<'ll, 'tcx>(
         span: Span,
         args: &[OperandRef<'tcx, &'ll Value>],
     ) -> Result<&'ll Value, ()> {
-        #[allow(unused_macro_rules)]
-        macro_rules! emit_error {
-            ($msg: tt) => {
-                emit_error!($msg, )
-            };
-            ($msg: tt, $($fmt: tt)*) => {
-                span_invalid_monomorphization_error(
-                    bx.sess(), span,
-                    &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
-                             name, $($fmt)*));
-            }
-        }
         macro_rules! return_error {
-            ($($fmt: tt)*) => {
-                {
-                    emit_error!($($fmt)*);
-                    return Err(());
-                }
-            }
+            ($diag: expr) => {{
+                bx.sess().emit_err($diag);
+                return Err(());
+            }};
         }
 
         let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
@@ -1194,16 +1167,15 @@ macro_rules! return_error {
             match f.bit_width() {
                 32 => ("f32", elem_ty),
                 64 => ("f64", elem_ty),
-                _ => {
-                    return_error!(
-                        "unsupported element type `{}` of floating-point vector `{}`",
-                        f.name_str(),
-                        in_ty
-                    );
-                }
+                _ => return_error!(InvalidMonomorphization::FloatingPointVector {
+                    span,
+                    name,
+                    f_ty: *f,
+                    in_ty,
+                }),
             }
         } else {
-            return_error!("`{}` is not a floating-point type", in_ty);
+            return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
         };
 
         let vec_ty = bx.type_vector(elem_ty, in_len);
@@ -1225,7 +1197,7 @@ macro_rules! return_error {
             sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
             sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
             sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
-            _ => return_error!("unrecognized intrinsic `{}`", name),
+            _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
         };
         let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
         let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
@@ -1319,37 +1291,48 @@ fn llvm_vector_ty<'ll>(
         // * M: any integer width is supported, will be truncated to i1
 
         // All types must be simd vector types
-        require_simd!(in_ty, "first");
-        require_simd!(arg_tys[1], "second");
-        require_simd!(arg_tys[2], "third");
-        require_simd!(ret_ty, "return");
+        require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
+        );
+        require_simd!(
+            arg_tys[2],
+            InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
+        );
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         // Of the same length:
         let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
-            "expected {} argument with length {} (same as input type `{}`), \
-             found `{}` with length {}",
-            "second",
-            in_len,
-            in_ty,
-            arg_tys[1],
-            out_len
+            InvalidMonomorphization::SecondArgumentLength {
+                span,
+                name,
+                in_len,
+                in_ty,
+                arg_ty: arg_tys[1],
+                out_len
+            }
         );
         require!(
             in_len == out_len2,
-            "expected {} argument with length {} (same as input type `{}`), \
-             found `{}` with length {}",
-            "third",
-            in_len,
-            in_ty,
-            arg_tys[2],
-            out_len2
+            InvalidMonomorphization::ThirdArgumentLength {
+                span,
+                name,
+                in_len,
+                in_ty,
+                arg_ty: arg_tys[2],
+                out_len: out_len2
+            }
         );
 
         // The return type must match the first argument type
-        require!(ret_ty == in_ty, "expected return type `{}`, found `{}`", in_ty, ret_ty);
+        require!(
+            ret_ty == in_ty,
+            InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
+        );
 
         // This counts how many pointers
         fn ptr_count(t: Ty<'_>) -> usize {
@@ -1376,15 +1359,15 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
             _ => {
                 require!(
                     false,
-                    "expected element type `{}` of second argument `{}` \
-                        to be a pointer to the element type `{}` of the first \
-                        argument `{}`, found `{}` != `*_ {}`",
-                    element_ty1,
-                    arg_tys[1],
-                    in_elem,
-                    in_ty,
-                    element_ty1,
-                    in_elem
+                    InvalidMonomorphization::ExpectedElementType {
+                        span,
+                        name,
+                        expected_element: element_ty1,
+                        second_arg: arg_tys[1],
+                        in_elem,
+                        in_ty,
+                        mutability: ExpectedPointerMutability::Not,
+                    }
                 );
                 unreachable!();
             }
@@ -1400,10 +1383,12 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
             _ => {
                 require!(
                     false,
-                    "expected element type `{}` of third argument `{}` \
-                                 to be a signed integer type",
-                    element_ty2,
-                    arg_tys[2]
+                    InvalidMonomorphization::ThirdArgElementType {
+                        span,
+                        name,
+                        expected_element: element_ty2,
+                        third_arg: arg_tys[2]
+                    }
                 );
             }
         }
@@ -1452,32 +1437,40 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
         // * M: any integer width is supported, will be truncated to i1
 
         // All types must be simd vector types
-        require_simd!(in_ty, "first");
-        require_simd!(arg_tys[1], "second");
-        require_simd!(arg_tys[2], "third");
+        require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
+        );
+        require_simd!(
+            arg_tys[2],
+            InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
+        );
 
         // Of the same length:
         let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
         require!(
             in_len == element_len1,
-            "expected {} argument with length {} (same as input type `{}`), \
-            found `{}` with length {}",
-            "second",
-            in_len,
-            in_ty,
-            arg_tys[1],
-            element_len1
+            InvalidMonomorphization::SecondArgumentLength {
+                span,
+                name,
+                in_len,
+                in_ty,
+                arg_ty: arg_tys[1],
+                out_len: element_len1
+            }
         );
         require!(
             in_len == element_len2,
-            "expected {} argument with length {} (same as input type `{}`), \
-            found `{}` with length {}",
-            "third",
-            in_len,
-            in_ty,
-            arg_tys[2],
-            element_len2
+            InvalidMonomorphization::ThirdArgumentLength {
+                span,
+                name,
+                in_len,
+                in_ty,
+                arg_ty: arg_tys[2],
+                out_len: element_len2
+            }
         );
 
         // This counts how many pointers
@@ -1508,15 +1501,15 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
             _ => {
                 require!(
                     false,
-                    "expected element type `{}` of second argument `{}` \
-                        to be a pointer to the element type `{}` of the first \
-                        argument `{}`, found `{}` != `*mut {}`",
-                    element_ty1,
-                    arg_tys[1],
-                    in_elem,
-                    in_ty,
-                    element_ty1,
-                    in_elem
+                    InvalidMonomorphization::ExpectedElementType {
+                        span,
+                        name,
+                        expected_element: element_ty1,
+                        second_arg: arg_tys[1],
+                        in_elem,
+                        in_ty,
+                        mutability: ExpectedPointerMutability::Mut,
+                    }
                 );
                 unreachable!();
             }
@@ -1531,10 +1524,12 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
             _ => {
                 require!(
                     false,
-                    "expected element type `{}` of third argument `{}` \
-                         be a signed integer type",
-                    element_ty2,
-                    arg_tys[2]
+                    InvalidMonomorphization::ThirdArgElementType {
+                        span,
+                        name,
+                        expected_element: element_ty2,
+                        third_arg: arg_tys[2]
+                    }
                 );
             }
         }
@@ -1581,10 +1576,7 @@ macro_rules! arith_red {
             if name == sym::$name {
                 require!(
                     ret_ty == in_elem,
-                    "expected return type `{}` (element of input `{}`), found `{}`",
-                    in_elem,
-                    in_ty,
-                    ret_ty
+                    InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
                 );
                 return match in_elem.kind() {
                     ty::Int(_) | ty::Uint(_) => {
@@ -1607,25 +1599,28 @@ macro_rules! arith_red {
                                 32 => bx.const_real(bx.type_f32(), $identity),
                                 64 => bx.const_real(bx.type_f64(), $identity),
                                 v => return_error!(
-                                    r#"
-unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
-                                    sym::$name,
-                                    in_ty,
-                                    in_elem,
-                                    v,
-                                    ret_ty
+                                    InvalidMonomorphization::UnsupportedSymbolOfSize {
+                                        span,
+                                        name,
+                                        symbol: sym::$name,
+                                        in_ty,
+                                        in_elem,
+                                        size: v,
+                                        ret_ty
+                                    }
                                 ),
                             }
                         };
                         Ok(bx.$float_reduce(acc, args[0].immediate()))
                     }
-                    _ => return_error!(
-                        "unsupported {} from `{}` with element `{}` to `{}`",
-                        sym::$name,
+                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+                        span,
+                        name,
+                        symbol: sym::$name,
                         in_ty,
                         in_elem,
                         ret_ty
-                    ),
+                    }),
                 };
             }
         };
@@ -1653,22 +1648,20 @@ macro_rules! minmax_red {
             if name == sym::$name {
                 require!(
                     ret_ty == in_elem,
-                    "expected return type `{}` (element of input `{}`), found `{}`",
-                    in_elem,
-                    in_ty,
-                    ret_ty
+                    InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
                 );
                 return match in_elem.kind() {
                     ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
                     ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
                     ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())),
-                    _ => return_error!(
-                        "unsupported {} from `{}` with element `{}` to `{}`",
-                        sym::$name,
+                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+                        span,
+                        name,
+                        symbol: sym::$name,
                         in_ty,
                         in_elem,
                         ret_ty
-                    ),
+                    }),
                 };
             }
         };
@@ -1686,22 +1679,20 @@ macro_rules! bitwise_red {
                 let input = if !$boolean {
                     require!(
                         ret_ty == in_elem,
-                        "expected return type `{}` (element of input `{}`), found `{}`",
-                        in_elem,
-                        in_ty,
-                        ret_ty
+                        InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
                     );
                     args[0].immediate()
                 } else {
                     match in_elem.kind() {
                         ty::Int(_) | ty::Uint(_) => {}
-                        _ => return_error!(
-                            "unsupported {} from `{}` with element `{}` to `{}`",
-                            sym::$name,
+                        _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+                            span,
+                            name,
+                            symbol: sym::$name,
                             in_ty,
                             in_elem,
                             ret_ty
-                        ),
+                        }),
                     }
 
                     // boolean reductions operate on vectors of i1s:
@@ -1714,13 +1705,14 @@ macro_rules! bitwise_red {
                         let r = bx.$red(input);
                         Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
                     }
-                    _ => return_error!(
-                        "unsupported {} from `{}` with element `{}` to `{}`",
-                        sym::$name,
+                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+                        span,
+                        name,
+                        symbol: sym::$name,
                         in_ty,
                         in_elem,
                         ret_ty
-                    ),
+                    }),
                 };
             }
         };
@@ -1733,16 +1725,18 @@ macro_rules! bitwise_red {
     bitwise_red!(simd_reduce_any: vector_reduce_or, true);
 
     if name == sym::simd_cast_ptr {
-        require_simd!(ret_ty, "return");
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
-            "expected return type with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
-            in_len,
-            in_ty,
-            ret_ty,
-            out_len
+            InvalidMonomorphization::ReturnLengthInputType {
+                span,
+                name,
+                in_len,
+                in_ty,
+                ret_ty,
+                out_len
+            }
         );
 
         match in_elem.kind() {
@@ -1751,9 +1745,14 @@ macro_rules! bitwise_red {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
                 assert!(!check_sized); // we are in codegen, so we shouldn't see these types
-                require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem)
+                require!(
+                    metadata.is_unit(),
+                    InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
+                );
+            }
+            _ => {
+                return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
             }
-            _ => return_error!("expected pointer, got `{}`", in_elem),
         }
         match out_elem.kind() {
             ty::RawPtr(p) => {
@@ -1761,9 +1760,14 @@ macro_rules! bitwise_red {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
                 assert!(!check_sized); // we are in codegen, so we shouldn't see these types
-                require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem)
+                require!(
+                    metadata.is_unit(),
+                    InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }
+                );
+            }
+            _ => {
+                return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
             }
-            _ => return_error!("expected pointer, got `{}`", out_elem),
         }
 
         if in_elem == out_elem {
@@ -1774,66 +1778,76 @@ macro_rules! bitwise_red {
     }
 
     if name == sym::simd_expose_addr {
-        require_simd!(ret_ty, "return");
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
-            "expected return type with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
-            in_len,
-            in_ty,
-            ret_ty,
-            out_len
+            InvalidMonomorphization::ReturnLengthInputType {
+                span,
+                name,
+                in_len,
+                in_ty,
+                ret_ty,
+                out_len
+            }
         );
 
         match in_elem.kind() {
             ty::RawPtr(_) => {}
-            _ => return_error!("expected pointer, got `{}`", in_elem),
+            _ => {
+                return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
+            }
         }
         match out_elem.kind() {
             ty::Uint(ty::UintTy::Usize) => {}
-            _ => return_error!("expected `usize`, got `{}`", out_elem),
+            _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: out_elem }),
         }
 
         return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
     }
 
     if name == sym::simd_from_exposed_addr {
-        require_simd!(ret_ty, "return");
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
-            "expected return type with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
-            in_len,
-            in_ty,
-            ret_ty,
-            out_len
+            InvalidMonomorphization::ReturnLengthInputType {
+                span,
+                name,
+                in_len,
+                in_ty,
+                ret_ty,
+                out_len
+            }
         );
 
         match in_elem.kind() {
             ty::Uint(ty::UintTy::Usize) => {}
-            _ => return_error!("expected `usize`, got `{}`", in_elem),
+            _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
         }
         match out_elem.kind() {
             ty::RawPtr(_) => {}
-            _ => return_error!("expected pointer, got `{}`", out_elem),
+            _ => {
+                return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
+            }
         }
 
         return Ok(bx.inttoptr(args[0].immediate(), llret_ty));
     }
 
     if name == sym::simd_cast || name == sym::simd_as {
-        require_simd!(ret_ty, "return");
+        require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             in_len == out_len,
-            "expected return type with length {} (same as input type `{}`), \
-                  found `{}` with length {}",
-            in_len,
-            in_ty,
-            ret_ty,
-            out_len
+            InvalidMonomorphization::ReturnLengthInputType {
+                span,
+                name,
+                in_len,
+                in_ty,
+                ret_ty,
+                out_len
+            }
         );
         // casting cares about nominal type, not just structural type
         if in_elem == out_elem {
@@ -1912,11 +1926,14 @@ enum Style {
         }
         require!(
             false,
-            "unsupported cast from `{}` with element `{}` to `{}` with element `{}`",
-            in_ty,
-            in_elem,
-            ret_ty,
-            out_elem
+            InvalidMonomorphization::UnsupportedCast {
+                span,
+                name,
+                in_ty,
+                in_elem,
+                ret_ty,
+                out_elem
+            }
         );
     }
     macro_rules! arith_binary {
@@ -1928,10 +1945,10 @@ macro_rules! arith_binary {
                     })*
                     _ => {},
                 }
-                require!(false,
-                         "unsupported operation on `{}` with element `{}`",
-                         in_ty,
-                         in_elem)
+                require!(
+                    false,
+                    InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
+                );
             })*
         }
     }
@@ -1959,10 +1976,10 @@ macro_rules! arith_unary {
                     })*
                     _ => {},
                 }
-                require!(false,
-                         "unsupported operation on `{}` with element `{}`",
-                         in_ty,
-                         in_elem)
+                require!(
+                    false,
+                    InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
+                );
             })*
         }
     }
@@ -2000,12 +2017,12 @@ macro_rules! arith_unary {
             ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
             ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
             _ => {
-                return_error!(
-                    "expected element type `{}` of vector type `{}` \
-                     to be a signed or unsigned integer type",
-                    arg_tys[0].simd_size_and_type(bx.tcx()).1,
-                    arg_tys[0]
-                );
+                return_error!(InvalidMonomorphization::ExpectedVectorElementType {
+                    span,
+                    name,
+                    expected_element: arg_tys[0].simd_size_and_type(bx.tcx()).1,
+                    vector_type: arg_tys[0]
+                });
             }
         };
         let llvm_intrinsic = &format!(
index 345174fb595ab1de60c74441c44e3481730bdb7c..d1ad687e6aee32a2b3e30c17557e58e366efce87 100644 (file)
@@ -27,6 +27,7 @@ rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_data_structures = { path = "../rustc_data_structures" }
index edde1537b81e19bcbde989104bf83592b4aff038..8ca7103ed482cc5f7646537165823a4dbcf2041d 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -208,16 +208,16 @@ pub fn link_binary<'a>(
     Ok(())
 }
 
+// Crate type is not passed when calculating the dylibs to include for LTO. In that case all
+// crate types must use the same dependency formats.
 pub fn each_linked_rlib(
-    sess: &Session,
     info: &CrateInfo,
+    crate_type: Option<CrateType>,
     f: &mut dyn FnMut(CrateNum, &Path),
 ) -> Result<(), errors::LinkRlibError> {
     let crates = info.used_crates.iter();
-    let mut fmts = None;
 
-    let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
-    if lto_active {
+    let fmts = if crate_type.is_none() {
         for combination in info.dependency_formats.iter().combinations(2) {
             let (ty1, list1) = &combination[0];
             let (ty2, list2) = &combination[1];
@@ -230,27 +230,23 @@ pub fn each_linked_rlib(
                 });
             }
         }
-    }
-
-    for (ty, list) in info.dependency_formats.iter() {
-        match ty {
-            CrateType::Executable
-            | CrateType::Staticlib
-            | CrateType::Cdylib
-            | CrateType::ProcMacro => {
-                fmts = Some(list);
-                break;
-            }
-            CrateType::Dylib if lto_active => {
-                fmts = Some(list);
-                break;
-            }
-            _ => {}
+        if info.dependency_formats.is_empty() {
+            return Err(errors::LinkRlibError::MissingFormat);
         }
-    }
-    let Some(fmts) = fmts else {
-        return Err(errors::LinkRlibError::MissingFormat);
+        &info.dependency_formats[0].1
+    } else {
+        let fmts = info
+            .dependency_formats
+            .iter()
+            .find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None });
+
+        let Some(fmts) = fmts else {
+            return Err(errors::LinkRlibError::MissingFormat);
+        };
+
+        fmts
     };
+
     for &cnum in crates {
         match fmts.get(cnum.as_usize() - 1) {
             Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
@@ -516,64 +512,71 @@ fn link_staticlib<'a>(
     )?;
     let mut all_native_libs = vec![];
 
-    let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
-        let name = codegen_results.crate_info.crate_name[&cnum];
-        let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-
-        // Here when we include the rlib into our staticlib we need to make a
-        // decision whether to include the extra object files along the way.
-        // These extra object files come from statically included native
-        // libraries, but they may be cfg'd away with #[link(cfg(..))].
-        //
-        // This unstable feature, though, only needs liblibc to work. The only
-        // use case there is where musl is statically included in liblibc.rlib,
-        // so if we don't want the included version we just need to skip it. As
-        // a result the logic here is that if *any* linked library is cfg'd away
-        // we just skip all object files.
-        //
-        // Clearly this is not sufficient for a general purpose feature, and
-        // we'd want to read from the library's metadata to determine which
-        // object files come from where and selectively skip them.
-        let skip_object_files = native_libs.iter().any(|lib| {
-            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
-                && !relevant_lib(sess, lib)
-        });
+    let res = each_linked_rlib(
+        &codegen_results.crate_info,
+        Some(CrateType::Staticlib),
+        &mut |cnum, path| {
+            let name = codegen_results.crate_info.crate_name[&cnum];
+            let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
+
+            // Here when we include the rlib into our staticlib we need to make a
+            // decision whether to include the extra object files along the way.
+            // These extra object files come from statically included native
+            // libraries, but they may be cfg'd away with #[link(cfg(..))].
+            //
+            // This unstable feature, though, only needs liblibc to work. The only
+            // use case there is where musl is statically included in liblibc.rlib,
+            // so if we don't want the included version we just need to skip it. As
+            // a result the logic here is that if *any* linked library is cfg'd away
+            // we just skip all object files.
+            //
+            // Clearly this is not sufficient for a general purpose feature, and
+            // we'd want to read from the library's metadata to determine which
+            // object files come from where and selectively skip them.
+            let skip_object_files = native_libs.iter().any(|lib| {
+                matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+                    && !relevant_lib(sess, lib)
+            });
 
-        let lto = are_upstream_rust_objects_already_included(sess)
-            && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
+            let lto = are_upstream_rust_objects_already_included(sess)
+                && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
 
-        // Ignoring obj file starting with the crate name
-        // as simple comparison is not enough - there
-        // might be also an extra name suffix
-        let obj_start = name.as_str().to_owned();
+            // Ignoring obj file starting with the crate name
+            // as simple comparison is not enough - there
+            // might be also an extra name suffix
+            let obj_start = name.as_str().to_owned();
 
-        ab.add_archive(
-            path,
-            Box::new(move |fname: &str| {
-                // Ignore metadata files, no matter the name.
-                if fname == METADATA_FILENAME {
-                    return true;
-                }
+            ab.add_archive(
+                path,
+                Box::new(move |fname: &str| {
+                    // Ignore metadata files, no matter the name.
+                    if fname == METADATA_FILENAME {
+                        return true;
+                    }
 
-                // Don't include Rust objects if LTO is enabled
-                if lto && looks_like_rust_object_file(fname) {
-                    return true;
-                }
+                    // Don't include Rust objects if LTO is enabled
+                    if lto && looks_like_rust_object_file(fname) {
+                        return true;
+                    }
 
-                // Otherwise if this is *not* a rust object and we're skipping
-                // objects then skip this file
-                if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
-                    return true;
-                }
+                    // Otherwise if this is *not* a rust object and we're skipping
+                    // objects then skip this file
+                    if skip_object_files
+                        && (!fname.starts_with(&obj_start) || !fname.ends_with(".o"))
+                    {
+                        return true;
+                    }
 
-                // ok, don't skip this
-                false
-            }),
-        )
-        .unwrap();
+                    // ok, don't skip this
+                    false
+                }),
+            )
+            .unwrap();
 
-        all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
-    });
+            all_native_libs
+                .extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
+        },
+    );
     if let Err(e) = res {
         sess.emit_fatal(e);
     }
@@ -1354,7 +1357,8 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
     if !lib_args.is_empty() {
         sess.emit_note(errors::StaticLibraryNativeArtifacts);
         // Prefix for greppability
-        sess.emit_note(errors::NativeStaticLibs { arguments: lib_args.join(" ") });
+        // Note: This must not be translated as tools are allowed to depend on this exact string.
+        sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
     }
 }
 
@@ -2612,7 +2616,7 @@ fn add_static_crate<'a>(
             sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
 
         let mut archive = archive_builder_builder.new_archive_builder(sess);
-        if let Err(e) = archive.add_archive(
+        if let Err(error) = archive.add_archive(
             cratepath,
             Box::new(move |f| {
                 if f == METADATA_FILENAME {
@@ -2652,7 +2656,7 @@ fn add_static_crate<'a>(
                 false
             }),
         ) {
-            sess.fatal(&format!("failed to build archive from rlib: {}", e));
+            sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
         }
         if archive.build(&dst) {
             link_upstream(&dst);
@@ -2822,11 +2826,30 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
                     // Implement the "linker flavor" part of -Zgcc-ld
                     // by asking cc to use some kind of lld.
                     cmd.arg("-fuse-ld=lld");
+
                     if !flavor.is_gnu() {
                         // Tell clang to use a non-default LLD flavor.
                         // Gcc doesn't understand the target option, but we currently assume
                         // that gcc is not used for Apple and Wasm targets (#97402).
-                        cmd.arg(format!("--target={}", sess.target.llvm_target));
+                        //
+                        // Note that we don't want to do that by default on macOS: e.g. passing a
+                        // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
+                        // shown in issue #101653 and the discussion in PR #101792.
+                        //
+                        // It could be required in some cases of cross-compiling with
+                        // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+                        // which specific versions of clang, macOS SDK, host and target OS
+                        // combinations impact us here.
+                        //
+                        // So we do a simple first-approximation until we know more of what the
+                        // Apple targets require (and which would be handled prior to hitting this
+                        // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+                        // this should be manually passed if needed. We specify the target when
+                        // targeting a different linker flavor on macOS, and that's also always
+                        // the case when targeting WASM.
+                        if sess.target.linker_flavor != sess.host.linker_flavor {
+                            cmd.arg(format!("--target={}", sess.target.llvm_target));
+                        }
                     }
                 }
             }
index 1a7de1a184a9c1b642c3d8bdbbe67f964323753c..7aadcdd222877478e422c82843a7aba4e8fd7d1c 100644 (file)
@@ -1002,7 +1002,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     let sess = tcx.sess;
 
     let mut each_linked_rlib_for_lto = Vec::new();
-    drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+    drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
         if link::ignored_for_lto(sess, crate_info, cnum) {
             return;
         }
index 8b34be3858006f763849e55cb4954dd5c764464a..d318c15d34221231ef8843f97083094d054edb87 100644 (file)
@@ -5,6 +5,7 @@
     submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
 };
 use crate::common::{IntPredicate, RealPredicate, TypeKind};
+use crate::errors;
 use crate::meth;
 use crate::mir;
 use crate::mir::operand::OperandValue;
@@ -451,10 +452,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let Some(llfn) = cx.declare_c_main(llfty) else {
             // FIXME: We should be smart and show a better diagnostic here.
             let span = cx.tcx().def_span(rust_main_def_id);
-            cx.sess()
-                .struct_span_err(span, "entry symbol `main` declared multiple times")
-                .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
-                .emit();
+            cx.sess().emit_err(errors::MultipleMainFunctions { span });
             cx.sess().abort_if_errors();
             bug!();
         };
@@ -595,8 +593,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                 &metadata,
                 &exported_symbols::metadata_symbol_name(tcx),
             );
-            if let Err(err) = std::fs::write(&file_name, data) {
-                tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
+            if let Err(error) = std::fs::write(&file_name, data) {
+                tcx.sess.emit_fatal(errors::MetadataObjectFileWrite { error });
             }
             Some(CompiledModule {
                 name: metadata_cgu_name,
@@ -815,11 +813,7 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
         let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
         let windows_subsystem = subsystem.map(|subsystem| {
             if subsystem != sym::windows && subsystem != sym::console {
-                tcx.sess.fatal(&format!(
-                    "invalid windows subsystem `{}`, only \
-                                     `windows` and `console` are allowed",
-                    subsystem
-                ));
+                tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
             }
             subsystem.to_string()
         });
index 71f9179d02cca4d8755242083bf1e43b0e27812a..e1abb73a504a3bea8ce211910cc63bd15ffcbd75 100644 (file)
@@ -1,10 +1,8 @@
 #![allow(non_camel_case_types)]
 
-use rustc_errors::struct_span_err;
 use rustc_hir::LangItem;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
-use rustc_session::Session;
 use rustc_span::Span;
 
 use crate::base;
@@ -193,10 +191,6 @@ pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
-    struct_span_err!(a, b, E0511, "{}", c).emit();
-}
-
 pub fn asm_const_to_str<'tcx>(
     tcx: TyCtxt<'tcx>,
     sp: Span,
index 3ae6c531b4453bedb7b466291d3ef6bd6726ea07..1599ccbb2594c747e7ef31495e0c2171f5c06417 100644 (file)
@@ -93,6 +93,7 @@ fn push_debuginfo_type_name<'tcx>(
                     Err(e) => {
                         // Computing the layout can still fail here, e.g. if the target architecture
                         // cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
+                        // FIXME: migrate once `rustc_middle::mir::interpret::InterpError` is translatable.
                         tcx.sess.fatal(&format!("{}", e));
                     }
                 }
index 0620000201f0254f81ff6dd4200876324b02fd0a..d81252653dfe8094d9aafcf505075acb60a5f33c 100644 (file)
@@ -6,7 +6,9 @@
     IntoDiagnosticArg,
 };
 use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
 use rustc_span::{Span, Symbol};
+use rustc_type_ir::FloatTy;
 use std::borrow::Cow;
 use std::io::Error;
 use std::path::{Path, PathBuf};
@@ -444,12 +446,6 @@ pub struct UnableToRun<'a> {
 #[diag(codegen_ssa_static_library_native_artifacts)]
 pub struct StaticLibraryNativeArtifacts;
 
-#[derive(Diagnostic)]
-#[diag(codegen_ssa_native_static_libs)]
-pub struct NativeStaticLibs {
-    pub arguments: String,
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_link_script_unavailable)]
 pub struct LinkScriptUnavailable;
@@ -555,3 +551,432 @@ pub struct ExpectedUsedSymbol {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_multiple_main_functions)]
+#[help]
+pub struct MultipleMainFunctions {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_metadata_object_file_write)]
+pub struct MetadataObjectFileWrite {
+    pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_windows_subsystem)]
+pub struct InvalidWindowsSubsystem {
+    pub subsystem: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_erroneous_constant)]
+pub struct ErroneousConstant {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_polymorphic_constant_too_generic)]
+pub struct PolymorphicConstantTooGeneric {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_shuffle_indices_evaluation)]
+pub struct ShuffleIndicesEvaluation {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_missing_memory_ordering)]
+pub struct MissingMemoryOrdering;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_atomic_ordering)]
+pub struct UnknownAtomicOrdering;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_atomic_compare_exchange)]
+pub struct AtomicCompareExchange;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_atomic_operation)]
+pub struct UnknownAtomicOperation;
+
+#[derive(Diagnostic)]
+pub enum InvalidMonomorphization<'tcx> {
+    #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = "E0511")]
+    BasicIntegerType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = "E0511")]
+    BasicFloatType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = "E0511")]
+    FloatToIntUnchecked {
+        #[primary_span]
+        span: Span,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = "E0511")]
+    FloatingPointVector {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        f_ty: FloatTy,
+        in_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = "E0511")]
+    FloatingPointType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = "E0511")]
+    UnrecognizedIntrinsic {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = "E0511")]
+    SimdArgument {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = "E0511")]
+    SimdInput {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = "E0511")]
+    SimdFirst {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = "E0511")]
+    SimdSecond {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = "E0511")]
+    SimdThird {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = "E0511")]
+    SimdReturn {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = "E0511")]
+    InvalidBitmask {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        mask_ty: Ty<'tcx>,
+        expected_int_bits: u64,
+        expected_bytes: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = "E0511")]
+    ReturnLengthInputType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_len: u64,
+        in_ty: Ty<'tcx>,
+        ret_ty: Ty<'tcx>,
+        out_len: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = "E0511")]
+    SecondArgumentLength {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_len: u64,
+        in_ty: Ty<'tcx>,
+        arg_ty: Ty<'tcx>,
+        out_len: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = "E0511")]
+    ThirdArgumentLength {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_len: u64,
+        in_ty: Ty<'tcx>,
+        arg_ty: Ty<'tcx>,
+        out_len: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = "E0511")]
+    ReturnIntegerType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ret_ty: Ty<'tcx>,
+        out_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = "E0511")]
+    SimdShuffle {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_return_length, code = "E0511")]
+    ReturnLength {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_len: u64,
+        ret_ty: Ty<'tcx>,
+        out_len: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_return_element, code = "E0511")]
+    ReturnElement {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_elem: Ty<'tcx>,
+        in_ty: Ty<'tcx>,
+        ret_ty: Ty<'tcx>,
+        out_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = "E0511")]
+    ShuffleIndexNotConstant {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        arg_idx: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = "E0511")]
+    ShuffleIndexOutOfBounds {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        arg_idx: u64,
+        total_len: u128,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = "E0511")]
+    InsertedType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_elem: Ty<'tcx>,
+        in_ty: Ty<'tcx>,
+        out_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_return_type, code = "E0511")]
+    ReturnType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_elem: Ty<'tcx>,
+        in_ty: Ty<'tcx>,
+        ret_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = "E0511")]
+    ExpectedReturnType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_ty: Ty<'tcx>,
+        ret_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = "E0511")]
+    MismatchedLengths {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        m_len: u64,
+        v_len: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = "E0511")]
+    MaskType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = "E0511")]
+    VectorArgument {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_ty: Ty<'tcx>,
+        in_elem: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = "E0511")]
+    CannotReturn {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ret_ty: Ty<'tcx>,
+        expected_int_bits: u64,
+        expected_bytes: u64,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = "E0511")]
+    ExpectedElementType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        expected_element: Ty<'tcx>,
+        second_arg: Ty<'tcx>,
+        in_elem: Ty<'tcx>,
+        in_ty: Ty<'tcx>,
+        mutability: ExpectedPointerMutability,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = "E0511")]
+    ThirdArgElementType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        expected_element: Ty<'tcx>,
+        third_arg: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = "E0511")]
+    UnsupportedSymbolOfSize {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        symbol: Symbol,
+        in_ty: Ty<'tcx>,
+        in_elem: Ty<'tcx>,
+        size: u64,
+        ret_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = "E0511")]
+    UnsupportedSymbol {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        symbol: Symbol,
+        in_ty: Ty<'tcx>,
+        in_elem: Ty<'tcx>,
+        ret_ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = "E0511")]
+    CastFatPointer {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = "E0511")]
+    ExpectedPointer {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = "E0511")]
+    ExpectedUsize {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        ty: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = "E0511")]
+    UnsupportedCast {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_ty: Ty<'tcx>,
+        in_elem: Ty<'tcx>,
+        ret_ty: Ty<'tcx>,
+        out_elem: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = "E0511")]
+    UnsupportedOperation {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        in_ty: Ty<'tcx>,
+        in_elem: Ty<'tcx>,
+    },
+
+    #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = "E0511")]
+    ExpectedVectorElementType {
+        #[primary_span]
+        span: Span,
+        name: Symbol,
+        expected_element: Ty<'tcx>,
+        vector_type: Ty<'tcx>,
+    },
+}
+
+pub enum ExpectedPointerMutability {
+    Mut,
+    Not,
+}
+
+impl IntoDiagnosticArg for ExpectedPointerMutability {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        match self {
+            ExpectedPointerMutability::Mut => DiagnosticArgValue::Str(Cow::Borrowed("*mut")),
+            ExpectedPointerMutability::Not => DiagnosticArgValue::Str(Cow::Borrowed("*_")),
+        }
+    }
+}
index 53ff3c24096262207ff95b19e35f1142ca2b2c71..14fe84a146da0792144787ee67a46f049a46dfa9 100644 (file)
@@ -1,3 +1,4 @@
+use crate::errors;
 use crate::mir::operand::OperandRef;
 use crate::traits::*;
 use rustc_middle::mir;
@@ -44,10 +45,14 @@ pub fn eval_mir_constant(
         self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
             match err {
                 ErrorHandled::Reported(_) => {
-                    self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
+                    self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
                 }
                 ErrorHandled::TooGeneric => {
-                    span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
+                    self.cx
+                        .tcx()
+                        .sess
+                        .diagnostic()
+                        .emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
                 }
             }
             err
@@ -87,7 +92,7 @@ pub fn simd_shuffle_indices(
                 (llval, c.ty())
             })
             .unwrap_or_else(|_| {
-                bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
+                bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span });
                 // We've errored, so we don't have to produce working code.
                 let ty = self.monomorphize(ty);
                 let llty = bx.backend_type(bx.layout_of(ty));
index a75609260eda49f874c909be5583d6693d98c148..766dc74cbbb6a39e66dd5dbacd6c82b80a821125 100644 (file)
@@ -1,7 +1,9 @@
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
 use super::FunctionCx;
-use crate::common::{span_invalid_monomorphization_error, IntPredicate};
+use crate::common::IntPredicate;
+use crate::errors;
+use crate::errors::InvalidMonomorphization;
 use crate::glue;
 use crate::meth;
 use crate::traits::*;
@@ -305,15 +307,7 @@ pub fn codegen_intrinsic_call(
                         _ => bug!(),
                     },
                     None => {
-                        span_invalid_monomorphization_error(
-                            bx.tcx().sess,
-                            span,
-                            &format!(
-                                "invalid monomorphization of `{}` intrinsic: \
-                                      expected basic integer type, found `{}`",
-                                name, ty
-                            ),
-                        );
+                        bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
                         return;
                     }
                 }
@@ -329,15 +323,7 @@ pub fn codegen_intrinsic_call(
                         _ => bug!(),
                     },
                     None => {
-                        span_invalid_monomorphization_error(
-                            bx.tcx().sess,
-                            span,
-                            &format!(
-                                "invalid monomorphization of `{}` intrinsic: \
-                                      expected basic float type, found `{}`",
-                                name, arg_tys[0]
-                            ),
-                        );
+                        bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] });
                         return;
                     }
                 }
@@ -345,29 +331,11 @@ pub fn codegen_intrinsic_call(
 
             sym::float_to_int_unchecked => {
                 if float_type_width(arg_tys[0]).is_none() {
-                    span_invalid_monomorphization_error(
-                        bx.tcx().sess,
-                        span,
-                        &format!(
-                            "invalid monomorphization of `float_to_int_unchecked` \
-                                  intrinsic: expected basic float type, \
-                                  found `{}`",
-                            arg_tys[0]
-                        ),
-                    );
+                    bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] });
                     return;
                 }
                 let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
-                    span_invalid_monomorphization_error(
-                        bx.tcx().sess,
-                        span,
-                        &format!(
-                            "invalid monomorphization of `float_to_int_unchecked` \
-                                    intrinsic:  expected basic integer type, \
-                                    found `{}`",
-                            ret_ty
-                        ),
-                    );
+                    bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty });
                     return;
                 };
                 if signed {
@@ -402,7 +370,7 @@ pub fn codegen_intrinsic_call(
                 use crate::common::{AtomicRmwBinOp, SynchronizationScope};
 
                 let Some((instruction, ordering)) = atomic.split_once('_') else {
-                    bx.sess().fatal("Atomic intrinsic missing memory ordering");
+                    bx.sess().emit_fatal(errors::MissingMemoryOrdering);
                 };
 
                 let parse_ordering = |bx: &Bx, s| match s {
@@ -412,25 +380,17 @@ pub fn codegen_intrinsic_call(
                     "release" => Release,
                     "acqrel" => AcquireRelease,
                     "seqcst" => SequentiallyConsistent,
-                    _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
+                    _ => bx.sess().emit_fatal(errors::UnknownAtomicOrdering),
                 };
 
                 let invalid_monomorphization = |ty| {
-                    span_invalid_monomorphization_error(
-                        bx.tcx().sess,
-                        span,
-                        &format!(
-                            "invalid monomorphization of `{}` intrinsic: \
-                                  expected basic integer type, found `{}`",
-                            name, ty
-                        ),
-                    );
+                    bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
                 };
 
                 match instruction {
                     "cxchg" | "cxchgweak" => {
                         let Some((success, failure)) = ordering.split_once('_') else {
-                            bx.sess().fatal("Atomic compare-exchange intrinsic missing failure memory ordering");
+                            bx.sess().emit_fatal(errors::AtomicCompareExchange);
                         };
                         let ty = substs.type_at(0);
                         if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
@@ -529,7 +489,7 @@ pub fn codegen_intrinsic_call(
                             "min" => AtomicRmwBinOp::AtomicMin,
                             "umax" => AtomicRmwBinOp::AtomicUMax,
                             "umin" => AtomicRmwBinOp::AtomicUMin,
-                            _ => bx.sess().fatal("unknown atomic operation"),
+                            _ => bx.sess().emit_fatal(errors::UnknownAtomicOperation),
                         };
 
                         let ty = substs.type_at(0);
index 655ec345ed3777197a771a038839b9b01ef6861a..0a90572d39e30cec6545b4124ea30dd5820e3cba 100644 (file)
@@ -115,7 +115,7 @@ fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     let local_def_id = def_id.expect_local();
     let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
 
-    let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
+    let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false };
     let parent_def = tcx.hir().get(parent);
 
     if !matches!(
index 94a8c1fc051dd6f3bb9aedcab3b33a74e0adca80..ea2a4388b92f00296193d9403601669f9b5379cc 100644 (file)
@@ -277,12 +277,12 @@ pub fn is_reachable(&self, node: Node) -> bool {
     }
 
     pub fn immediate_dominator(&self, node: Node) -> Node {
-        assert!(self.is_reachable(node), "node {:?} is not reachable", node);
+        assert!(self.is_reachable(node), "node {node:?} is not reachable");
         self.immediate_dominators[node].unwrap()
     }
 
     pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
-        assert!(self.is_reachable(node), "node {:?} is not reachable", node);
+        assert!(self.is_reachable(node), "node {node:?} is not reachable");
         Iter { dominators: self, node: Some(node) }
     }
 
index b31092eca9837bb0a0c5536b1be7e05c188fcbf5..c8e66eb672cc29b6a7b4dc670ae9e4d49ce7d3db 100644 (file)
@@ -233,10 +233,9 @@ fn construct(graph: &'c G) -> Sccs<G::Node, S> {
             .map(G::Node::new)
             .map(|node| match this.start_walk_from(node) {
                 WalkReturn::Complete { scc_index } => scc_index,
-                WalkReturn::Cycle { min_depth } => panic!(
-                    "`start_walk_node({:?})` returned cycle with depth {:?}",
-                    node, min_depth
-                ),
+                WalkReturn::Cycle { min_depth } => {
+                    panic!("`start_walk_node({node:?})` returned cycle with depth {min_depth:?}")
+                }
             })
             .collect();
 
@@ -272,8 +271,7 @@ fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<S>> {
             NodeState::NotVisited => return None,
 
             NodeState::InCycleWith { parent } => panic!(
-                "`find_state` returned `InCycleWith({:?})`, which ought to be impossible",
-                parent
+                "`find_state` returned `InCycleWith({parent:?})`, which ought to be impossible"
             ),
         })
     }
@@ -369,7 +367,7 @@ fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, S> {
                     previous_node = previous;
                 }
                 // Only InCycleWith nodes were added to the reverse linked list.
-                other => panic!("Invalid previous link while compressing cycle: {:?}", other),
+                other => panic!("Invalid previous link while compressing cycle: {other:?}"),
             }
 
             debug!("find_state: parent_state = {:?}", node_state);
@@ -394,7 +392,7 @@ fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, S> {
                 // NotVisited can not be part of a cycle since it should
                 // have instead gotten explored.
                 NodeState::NotVisited | NodeState::InCycleWith { .. } => {
-                    panic!("invalid parent state: {:?}", node_state)
+                    panic!("invalid parent state: {node_state:?}")
                 }
             }
         }
index 3a268e4b4f43224a5f60a8fbeee19feaaaa1c608..4b6aa116520df9f91ab1f98800c6d374dd631a6a 100644 (file)
@@ -30,7 +30,7 @@ pub fn dump_graphviz<P: AsRef<Path>>(&self, dir: P, description: &str) {
 
         let counter = COUNTER.fetch_add(1, Ordering::AcqRel);
 
-        let file_path = dir.as_ref().join(format!("{:010}_{}.gv", counter, description));
+        let file_path = dir.as_ref().join(format!("{counter:010}_{description}.gv"));
 
         let mut gv_file = BufWriter::new(File::create(file_path).unwrap());
 
@@ -47,7 +47,7 @@ fn graph_id(&self) -> dot::Id<'_> {
     }
 
     fn node_id(&self, index: &Self::Node) -> dot::Id<'_> {
-        dot::Id::new(format!("obligation_{}", index)).unwrap()
+        dot::Id::new(format!("obligation_{index}")).unwrap()
     }
 
     fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> {
index 16296b2248975e6eb627a3d9ceb21ed967a6bb42..393f173908128457c7f70f01c8eddbbc8240c7cf 100644 (file)
@@ -545,7 +545,7 @@ pub fn new(
         // length can behave as a source of entropy for heap addresses, when
         // ASLR is disabled and the heap is otherwise determinic.
         let pid: u32 = process::id();
-        let filename = format!("{}-{:07}.rustc_profile", crate_name, pid);
+        let filename = format!("{crate_name}-{pid:07}.rustc_profile");
         let path = output_directory.join(&filename);
         let profiler =
             Profiler::with_counter(&path, measureme::counters::Counter::by_name(counter_name)?)?;
index 3a8ab8ff9911e4a34d2b9d01027dec1d328c7b01..719e4e3d97443c937381903fb23e8bbb29eaa58f 100644 (file)
@@ -30,7 +30,7 @@ pub fn new(s: &str) -> SmallCStr {
             SmallVec::from_vec(data)
         };
         if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
-            panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
+            panic!("The string \"{s}\" cannot be converted into a CStr: {e}");
         }
         SmallCStr { data }
     }
@@ -39,7 +39,7 @@ pub fn new(s: &str) -> SmallCStr {
     pub fn new_with_nul(s: &str) -> SmallCStr {
         let b = s.as_bytes();
         if let Err(e) = ffi::CStr::from_bytes_with_nul(b) {
-            panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
+            panic!("The string \"{s}\" cannot be converted into a CStr: {e}");
         }
         SmallCStr { data: SmallVec::from_slice(s.as_bytes()) }
     }
@@ -74,7 +74,7 @@ fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
             iter.into_iter().flat_map(|s| s.as_bytes()).copied().collect::<SmallVec<_>>();
         data.push(0);
         if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
-            panic!("The iterator {:?} cannot be converted into a CStr: {}", data, e);
+            panic!("The iterator {data:?} cannot be converted into a CStr: {e}");
         }
         Self { data }
     }
index 05f059c89d5cd0fea01ea73e00e8d8419b4b3c9e..c63caa06818f26e2f3f263d778c140ae5fc588aa 100644 (file)
@@ -1,6 +1,7 @@
 use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
+use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
@@ -16,7 +17,7 @@
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct SortedMap<K, V> {
     data: Vec<(K, V)>,
 }
@@ -314,5 +315,11 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
+impl<K: Debug, V: Debug> Debug for SortedMap<K, V> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish()
+    }
+}
+
 #[cfg(test)]
 mod tests;
index 2417df66bb9d8a2b0dd0d4ac09744a0d8dba0cdc..d1a99bcaeb75452a28b497c99f1bddddea8ecd3e 100644 (file)
@@ -71,8 +71,7 @@ pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) ->
         // This should return just one element, otherwise it's a bug
         assert!(
             filter.next().is_none(),
-            "Collection {:#?} should have just one matching element",
-            self
+            "Collection {self:#?} should have just one matching element"
         );
         Some(value)
     }
index 01338359f1af1d063ddc3d16130fc221a31657f4..42c97cc6a9d7418be734945a66ed3009a5004337 100644 (file)
@@ -25,7 +25,7 @@ pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
             Ok(arg) => args.extend(arg),
             Err(err) => rustc_session::early_error(
                 rustc_session::config::ErrorOutputType::default(),
-                &format!("Failed to load argument file: {}", err),
+                &format!("Failed to load argument file: {err}"),
             ),
         }
     }
@@ -42,8 +42,8 @@ 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),
+            Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"),
+            Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"),
         }
     }
 }
index 31e08c44d29812a12d2a62fbc34d4cbd0fa435d8..3cbe0052359b332971a8e4638bc40821dc8c4b72 100644 (file)
@@ -486,11 +486,8 @@ pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
 
 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{0:0>4}", code)
-    };
+    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;
@@ -513,14 +510,14 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
             if io::stdout().is_terminal() {
                 show_content_with_pager(&text);
             } else {
-                print!("{}", text);
+                print!("{text}");
             }
         }
         Ok(None) => {
-            early_error(output, &format!("no extended information for {}", code));
+            early_error(output, &format!("no extended information for {code}"));
         }
         Err(InvalidErrorCode) => {
-            early_error(output, &format!("{} is not a valid error code", code));
+            early_error(output, &format!("{code} is not a valid error code"));
         }
     }
 }
@@ -552,7 +549,7 @@ fn show_content_with_pager(content: &str) {
     // If pager fails for whatever reason, we should still print the content
     // to standard output
     if fallback_to_println {
-        print!("{}", content);
+        print!("{content}");
     }
 }
 
@@ -672,7 +669,7 @@ fn print_crate_info(
                 );
                 let id = rustc_session::output::find_crate_name(sess, attrs, input);
                 if *req == PrintRequest::CrateName {
-                    println!("{}", id);
+                    println!("{id}");
                     continue;
                 }
                 let crate_types = collect_crate_types(sess, attrs);
@@ -704,7 +701,7 @@ fn print_crate_info(
                         }
 
                         if let Some(value) = value {
-                            Some(format!("{}=\"{}\"", name, value))
+                            Some(format!("{name}=\"{value}\""))
                         } else {
                             Some(name.to_string())
                         }
@@ -713,7 +710,7 @@ fn print_crate_info(
 
                 cfgs.sort();
                 for cfg in cfgs {
-                    println!("{}", cfg);
+                    println!("{cfg}");
                 }
             }
             CallingConventions => {
@@ -739,7 +736,7 @@ fn print_crate_info(
                     let stable = sess.target.options.supported_split_debuginfo.contains(split);
                     let unstable_ok = sess.unstable_options();
                     if stable || unstable_ok {
-                        println!("{}", split);
+                        println!("{split}");
                     }
                 }
             }
@@ -776,14 +773,14 @@ pub fn version_at_macro_invocation(
 ) {
     let verbose = matches.opt_present("verbose");
 
-    println!("{} {}", binary, version);
+    println!("{binary} {version}");
 
     if verbose {
-        println!("binary: {}", binary);
-        println!("commit-hash: {}", commit_hash);
-        println!("commit-date: {}", commit_date);
+        println!("binary: {binary}");
+        println!("commit-hash: {commit_hash}");
+        println!("commit-date: {commit_date}");
         println!("host: {}", config::host_triple());
-        println!("release: {}", release);
+        println!("release: {release}");
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@@ -1037,7 +1034,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
                 .map(|&(name, ..)| ('C', name))
                 .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name)))
                 .find(|&(_, name)| *opt == name.replace('_', "-"))
-                .map(|(flag, _)| format!("{}. Did you mean `-{} {}`?", e, flag, opt)),
+                .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
             _ => None,
         };
         early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string()));
@@ -1148,7 +1145,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
             } else {
                 result.push(a.to_string());
                 match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
-                    Some(s) => result.push(format!("{}=[REDACTED]", s)),
+                    Some(s) => result.push(format!("{s}=[REDACTED]")),
                     None => result.push(content),
                 }
             }
@@ -1199,8 +1196,8 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
             };
 
             // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            // Don't do this for `ExplicitBug`, which has an unhelpful message and backtrace.
-            if !info.payload().is::<rustc_errors::ExplicitBug>() {
+            // Don't do this for `GoodPathBug`, which already emits its own more useful backtrace.
+            if !info.payload().is::<rustc_errors::GoodPathBug>() {
                 (*DEFAULT_HOOK)(info);
 
                 // Separate the output with an empty line
@@ -1237,14 +1234,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
 
     // a .span_bug or .bug call has already printed what
     // it wants to print.
-    if !info.payload().is::<rustc_errors::ExplicitBug>() {
+    if !info.payload().is::<rustc_errors::ExplicitBug>()
+        && !info.payload().is::<rustc_errors::GoodPathBug>()
+    {
         let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
         handler.emit_diagnostic(&mut d);
     }
 
     let mut xs: Vec<Cow<'static, str>> = vec![
         "the compiler unexpectedly panicked. this is a bug.".into(),
-        format!("we would appreciate a bug report: {}", bug_report_url).into(),
+        format!("we would appreciate a bug report: {bug_report_url}").into(),
         format!(
             "rustc {} running on {}",
             util::version_str!().unwrap_or("unknown_version"),
@@ -1377,7 +1376,7 @@ pub fn main() -> ! {
                 arg.into_string().unwrap_or_else(|arg| {
                     early_error(
                         ErrorOutputType::default(),
-                        &format!("argument {} is not valid Unicode: {:?}", i, arg),
+                        &format!("argument {i} is not valid Unicode: {arg:?}"),
                     )
                 })
             })
index f9b1316d2eb5f632da4474ae56720ff1881cbf40..b2451bc730f79f7eb1ddea06cf54708d1dc24f52 100644 (file)
@@ -360,7 +360,7 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
 
 fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
     match ofile {
-        None => print!("{}", out),
+        None => print!("{out}"),
         Some(p) => {
             if let Err(e) = std::fs::write(p, out) {
                 sess.emit_fatal(UnprettyDumpFail {
@@ -402,7 +402,7 @@ pub fn print_after_parsing(
         }
         AstTree(PpAstTreeMode::Normal) => {
             debug!("pretty printing AST tree");
-            format!("{:#?}", krate)
+            format!("{krate:#?}")
         }
         _ => unreachable!(),
     };
@@ -446,7 +446,7 @@ pub fn print_after_hir_lowering<'tcx>(
 
         AstTree(PpAstTreeMode::Expanded) => {
             debug!("pretty-printing expanded AST");
-            format!("{:#?}", krate)
+            format!("{krate:#?}")
         }
 
         Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
index d05559e92440f28f5eb2b7197991b30f74e39392..686c22bc386dc3fff72e8366b1bab0a5c6669662 100644 (file)
 E0205: include_str!("./error_codes/E0205.md"),
 E0206: include_str!("./error_codes/E0206.md"),
 E0207: include_str!("./error_codes/E0207.md"),
+E0208: include_str!("./error_codes/E0208.md"),
 E0210: include_str!("./error_codes/E0210.md"),
 E0211: include_str!("./error_codes/E0211.md"),
 E0212: include_str!("./error_codes/E0212.md"),
 E0458: include_str!("./error_codes/E0458.md"),
 E0459: include_str!("./error_codes/E0459.md"),
 E0460: include_str!("./error_codes/E0460.md"),
+E0461: include_str!("./error_codes/E0461.md"),
 E0462: include_str!("./error_codes/E0462.md"),
 E0463: include_str!("./error_codes/E0463.md"),
 E0464: include_str!("./error_codes/E0464.md"),
 E0510: include_str!("./error_codes/E0510.md"),
 E0511: include_str!("./error_codes/E0511.md"),
 E0512: include_str!("./error_codes/E0512.md"),
+E0514: include_str!("./error_codes/E0514.md"),
 E0515: include_str!("./error_codes/E0515.md"),
 E0516: include_str!("./error_codes/E0516.md"),
 E0517: include_str!("./error_codes/E0517.md"),
 E0518: include_str!("./error_codes/E0518.md"),
+E0519: include_str!("./error_codes/E0519.md"),
 E0520: include_str!("./error_codes/E0520.md"),
 E0521: include_str!("./error_codes/E0521.md"),
 E0522: include_str!("./error_codes/E0522.md"),
 E0637: include_str!("./error_codes/E0637.md"),
 E0638: include_str!("./error_codes/E0638.md"),
 E0639: include_str!("./error_codes/E0639.md"),
+E0640: include_str!("./error_codes/E0640.md"),
 E0641: include_str!("./error_codes/E0641.md"),
 E0642: include_str!("./error_codes/E0642.md"),
 E0643: include_str!("./error_codes/E0643.md"),
 E0714: include_str!("./error_codes/E0714.md"),
 E0715: include_str!("./error_codes/E0715.md"),
 E0716: include_str!("./error_codes/E0716.md"),
+E0711: include_str!("./error_codes/E0711.md"),
+E0717: include_str!("./error_codes/E0717.md"),
 E0718: include_str!("./error_codes/E0718.md"),
 E0719: include_str!("./error_codes/E0719.md"),
 E0720: include_str!("./error_codes/E0720.md"),
 //  E0190, // deprecated: can only cast a &-pointer to an &-object
 //  E0194, // merged into E0403
 //  E0196, // cannot determine a type for this closure
-    E0208, // internal error code
 //  E0209, // builtin traits can only be implemented on structs or enums
 //  E0213, // associated types are not accepted in this context
 //  E0215, // angle-bracket notation is not stable with `Fn`
 //  E0300, // unexpanded macro
 //  E0304, // expected signed integer constant
 //  E0305, // expected constant
-    E0313, // lifetime of borrowed pointer outlives lifetime of captured
-           // variable
+//  E0313, // removed: found unreachable
 //  E0314, // closure outlives stack frame
 //  E0315, // cannot invoke closure outside of its lifetime
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
 //  E0421, // merged into 531
 //  E0427, // merged into 530
 //  E0456, // plugin `..` is not available for triple `..`
-    E0461, // couldn't find crate `..` with expected target triple ..
-    E0465, // multiple .. candidates for `..` found
+//  E0465, // removed: merged with E0464
 //  E0467, // removed
 //  E0470, // removed
 //  E0471, // constant evaluation error (in pattern)
 //  E0488, // lifetime of variable does not enclose its declaration
 //  E0489, // type/lifetime parameter not in scope here
     E0490, // a value of type `..` is borrowed for too long
-    E0514, // metadata version mismatch
-    E0519, // local crate and dependency have same (crate-name, disambiguator)
     E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
 //  E0526, // shuffle indices are not constant
 //  E0540, // multiple rustc_deprecated attributes
 //  E0629, // missing 'feature' (rustc_const_unstable)
 //  E0630, // rustc_const_unstable attribute must be paired with stable/unstable
            // attribute
-    E0640, // infer outlives requirements, internal error code
 //  E0645, // trait aliases not finished
 //  E0694, // an unknown tool name found in scoped attributes
 //  E0702, // replaced with a generic attribute input check
 //  E0707, // multiple elided lifetimes used in arguments of `async fn`
 //  E0709, // multiple different lifetimes used in arguments of `async fn`
-    E0711, // a feature has been declared with conflicting stability attributes, internal error code
-    E0717, // rustc_promotable without stability attribute, internal error code
 //  E0721, // `await` keyword
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
index 021a0219d13e2b60b8e79b49f3fb37132dc6789b..ac78f66adada052ae5b3487fa532bb4b8f65874a 100644 (file)
@@ -1,5 +1,4 @@
-A constant item was initialized with something that is not a constant
-expression.
+A non-`const` function was called in a `const` context.
 
 Erroneous code example:
 
@@ -8,26 +7,20 @@ fn create_some() -> Option<u8> {
     Some(1)
 }
 
-const FOO: Option<u8> = create_some(); // error!
+// error: cannot call non-const fn `create_some` in constants
+const FOO: Option<u8> = create_some();
 ```
 
-The only functions that can be called in static or constant expressions are
-`const` functions, and struct/enum constructors.
+All functions used in a `const` context (constant or static expression) must
+be marked `const`.
 
 To fix this error, you can declare `create_some` as a constant function:
 
 ```
-const fn create_some() -> Option<u8> { // declared as a const function
+// declared as a `const` function:
+const fn create_some() -> Option<u8> {
     Some(1)
 }
 
-const FOO: Option<u8> = create_some(); // ok!
-
-// These are also working:
-struct Bar {
-    x: u8,
-}
-
-const OTHER_FOO: Option<u8> = Some(1);
-const BAR: Bar = Bar {x: 1};
+const FOO: Option<u8> = create_some(); // no error!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md
new file mode 100644 (file)
index 0000000..7edd93e
--- /dev/null
@@ -0,0 +1 @@
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0461.md b/compiler/rustc_error_codes/src/error_codes/E0461.md
new file mode 100644 (file)
index 0000000..33105c4
--- /dev/null
@@ -0,0 +1,30 @@
+Couldn't find crate `..` with expected target triple `..`.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_type = "lib"]
+
+fn foo() {}
+```
+
+`main.rs`
+```ignore (cannot-link-with-other-tests)
+extern crate a;
+
+fn main() {
+    a::foo();
+}
+```
+
+`a.rs` is then compiled with `--target powerpc-unknown-linux-gnu` and `b.rs`
+with `--target x86_64-unknown-linux-gnu`. `a.rs` is compiled into a binary
+format incompatible with `b.rs`; PowerPC and x86 are totally different
+architectures. This issue also extends to any difference in target triples, as
+`std` is operating-system specific.
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager, automatically
+   fixing this issue.
+ * Recompiling either crate so that they target a consistent target triple.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0514.md b/compiler/rustc_error_codes/src/error_codes/E0514.md
new file mode 100644 (file)
index 0000000..ce2bbc5
--- /dev/null
@@ -0,0 +1,33 @@
+Dependency compiled with different version of `rustc`.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+// compiled with stable `rustc`
+
+#[crate_type = "lib"]
+```
+
+`b.rs`
+```ignore (cannot-link-with-other-tests)
+// compiled with nightly `rustc`
+
+#[crate_type = "lib"]
+
+extern crate a; // error: found crate `a` compiled by an incompatible version
+                //        of rustc
+```
+
+This error is caused when the version of `rustc` used to compile a crate, as
+stored in the binary's metadata, differs from the version of one of its
+dependencies. Many parts of Rust binaries are considered unstable. For
+instance, the Rust ABI is not stable between compiler versions. This means that
+the compiler cannot be sure about *how* to call a function between compiler
+versions, and therefore this error occurs.
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager and
+   [Rustup](https://rust-lang.github.io/rustup/), the Rust toolchain installer,
+   automatically fixing this issue.
+ * Recompiling the crates with a uniform `rustc` version.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0519.md b/compiler/rustc_error_codes/src/error_codes/E0519.md
new file mode 100644 (file)
index 0000000..12876e2
--- /dev/null
@@ -0,0 +1,40 @@
+The current crate is indistinguishable from one of its dependencies, in terms
+of metadata.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_name = "a"]
+#![crate_type = "lib"]
+
+pub fn foo() {}
+```
+
+`b.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_name = "a"]
+#![crate_type = "lib"]
+
+// error: the current crate is indistinguishable from one of its dependencies:
+//        it has the same crate-name `a` and was compiled with the same
+//        `-C metadata` arguments. This will result in symbol conflicts between
+//        the two.
+extern crate a;
+
+pub fn foo() {}
+
+fn bar() {
+    a::foo(); // is this calling the local crate or the dependency?
+}
+```
+
+The above example compiles two crates with exactly the same name and
+`crate_type` (plus any other metadata). This causes an error because it becomes
+impossible for the compiler to distinguish between symbols (`pub` item names).
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager, automatically
+   fixing this issue.
+ * Recompiling the crate with different metadata (different name/
+   `crate_type`).
index 040c7a02ef4db8f8418c9df3f07dd31c67bdc3bc..995d945f1589e0d16df7a12cc0e09b7573c6df93 100644 (file)
@@ -11,7 +11,7 @@ struct Aligned(i32);
 struct Packed(Aligned);
 ```
 
-Just like you cannot have both `align` and `packed` representation hints on a
+Just like you cannot have both `align` and `packed` representation hints on the
 same type, a `packed` type cannot contain another type with the `align`
 representation hint. However, you can do the opposite:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0640.md b/compiler/rustc_error_codes/src/error_codes/E0640.md
new file mode 100644 (file)
index 0000000..7edd93e
--- /dev/null
@@ -0,0 +1 @@
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0711.md b/compiler/rustc_error_codes/src/error_codes/E0711.md
new file mode 100644 (file)
index 0000000..a215003
--- /dev/null
@@ -0,0 +1,30 @@
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
+
+Feature declared with conflicting stability requirements.
+
+```compile_fail,E0711
+// NOTE: this attribute is perma-unstable and should *never* be used outside of
+//       stdlib and the compiler.
+#![feature(staged_api)]
+
+#![stable(feature = "...", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.0.0")]
+fn foo_stable_1_0_0() {}
+
+// error: feature `foo` is declared stable since 1.29.0
+#[stable(feature = "foo", since = "1.29.0")]
+fn foo_stable_1_29_0() {}
+
+// error: feature `foo` is declared unstable
+#[unstable(feature = "foo", issue = "none")]
+fn foo_unstable() {}
+```
+
+In the above example, the `foo` feature is first defined to be stable since
+1.0.0, but is then re-declared stable since 1.29.0. This discrepancy in
+versions causes an error. Furthermore, `foo` is then re-declared as unstable,
+again the conflict causes an error.
+
+This error can be fixed by splitting the feature, this allows any
+stability requirements and removes any possibility of conflict.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0717.md b/compiler/rustc_error_codes/src/error_codes/E0717.md
new file mode 100644 (file)
index 0000000..7edd93e
--- /dev/null
@@ -0,0 +1 @@
+#### This error code is internal to the compiler and will not be emitted with normal Rust code.
index 74f89080b91a16686b378a10e79c70e15439ec96..3891745b5008efaa8475462cdb2d21e050e29e84 100644 (file)
@@ -1,3 +1,5 @@
+#### Note: this error code is no longer emitted by the compiler
+
 Support for Non-Lexical Lifetimes (NLL) has been included in the Rust compiler
 since 1.31, and has been enabled on the 2015 edition since 1.36. The new borrow
 checker for NLL uncovered some bugs in the old borrow checker, which in some
index db4c82b35c77822d718d16039112205dada7972c..c8c7afb5f919632b8555682136978d0ea4dc4c99 100644 (file)
@@ -157,8 +157,6 @@ codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
 
 codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
 
-codegen_ssa_native_static_libs = native-static-libs: {$arguments}
-
 codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
 
 codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
@@ -194,3 +192,102 @@ codegen_ssa_unknown_archive_kind =
     Don't know how to build archive of type: {$kind}
 
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
+    .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+
+codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
+
+codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
+
+codegen_ssa_erroneous_constant = erroneous constant encountered
+
+codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
+
+codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
+
+codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
+
+codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
+
+codegen_ssa_unknown_atomic_operation = unknown atomic operation
+
+codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
+
+codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
+
+codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
+
+codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
+
+codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
+
+codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+
+codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
+
+codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
+
+codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
+
+codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
+
+codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
+
+codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+
+codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
+
+codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
+
+codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+
+codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
+
+codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
+
+codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
+
+codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
+
+codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
+
+codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
+
+codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
index c9d83746d5454debb5f9e21fb847cc1a3cd863bb..c1cb07cf0dfe8f97a6b58e53ab6199d50cd8e0a4 100644 (file)
@@ -172,3 +172,142 @@ infer_msl_unmet_req = because this has an unmet lifetime requirement
 infer_msl_trait_note = this has an implicit `'static` lifetime requirement
 infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
 infer_suggest_add_let_for_letchains = consider adding `let`
+
+infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
+    .label = lifetime `{$named}` required
+
+infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
+    .label = lifetime `{$named}` required
+
+infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
+
+infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
+
+infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
+infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
+infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`...
+infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
+infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
+infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
+    [true] ...
+    *[false] {""}
+}`{$ty_or_sig}` must implement `{$trait_path}`
+
+infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
+    [true] , for some specific lifetime `'{$lifetime}`
+    *[false] {""}
+}
+infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
+    [true] , for some specific lifetime `'{$lifetime}`
+    *[false] {""}
+}
+infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
+    [true] , for some specific lifetime `'{$lifetime}`
+    *[false] {""}
+}
+
+infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
+    .label_satisfy = doesn't satisfy where-clause
+    .label_where = due to a where-clause on `{$def_id}`...
+    .label_dup = implementation of `{$trait_def_id}` is not general enough
+
+infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
+    .found = found `{$found}`
+    .expected = expected `{$expected}`
+    .expected_found = expected signature `{$expected}`
+               {"   "}found signature `{$found}`
+
+infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
+infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+
+infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
+infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement
+infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
+infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+
+infer_but_calling_introduces = {$has_param_name ->
+    [true] `{$param_name}`
+    *[false] `fn` parameter
+} has {$lifetime_kind ->
+    [named] lifetime `{lifetime}`
+    *[anon] an anonymous lifetime `'_`
+} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
+    .label1 = {$has_lifetime ->
+        [named] lifetime `{lifetime}`
+        *[anon] an anonymous lifetime `'_`
+    }
+    .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
+        [named] `impl` of `{$impl_path}`
+        *[anon] inherent `impl`
+    }
+
+infer_but_needs_to_satisfy = {$has_param_name ->
+    [true] `{$param_name}`
+    *[false] `fn` parameter
+} has {$has_lifetime ->
+    [named] lifetime `{lifetime}`
+    *[anon] an anonymous lifetime `'_`
+} but it needs to satisfy a `'static` lifetime requirement
+    .influencer = this data with {$has_lifetime ->
+        [named] lifetime `{lifetime}`
+        *[anon] an anonymous lifetime `'_`
+    }...
+    .require = {$spans_empty ->
+        *[true] ...is used and required to live as long as `'static` here
+        [false] ...and is required to live as long as `'static` here
+    }
+    .used_here = ...is used here...
+    .introduced_by_bound = 'static` lifetime requirement introduced by this bound
+
+infer_more_targeted = {$has_param_name ->
+    [true] `{$param_name}`
+    *[false] `fn` parameter
+} has {$has_lifetime ->
+    [named] lifetime `{lifetime}`
+    *[anon] an anonymous lifetime `'_`
+} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
+
+infer_ril_introduced_here = `'static` requirement introduced here
+infer_ril_introduced_by = requirement introduced by this return type
+infer_ril_because_of = because of this returned expression
+infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
index b3ca540417da79876f17449c5a2d4aa82d767861..79b8b417257045a6b60f244acf4f4a0f7acc35d5 100644 (file)
@@ -4,6 +4,11 @@ metadata_rlib_required =
 metadata_lib_required =
     crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
 
+metadata_rustc_lib_required =
+    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+    .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+    .help = try adding `extern crate rustc_driver;` at the top level of this crate
+
 metadata_crate_dep_multiple =
     cannot satisfy dependencies so `{$crate_name}` only shows up once
     .help = having upstream crates all available in one format will likely make this go away
@@ -196,11 +201,7 @@ metadata_extern_location_not_file =
     extern location for {$crate_name} is not a file: {$location}
 
 metadata_multiple_candidates =
-    multiple {$flavor} candidates for `{$crate_name}` found
-
-metadata_multiple_matching_crates =
-    multiple matching crates for `{$crate_name}`
-    .note = candidates:{$candidates}
+    multiple candidates for `{$flavor}` dependency `{$crate_name}` found
 
 metadata_symbol_conflicts_current =
     the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
index b53550e5fd556c02e58acd21fbae26252bb2b69a..3401978caf5f0f305b0f6128baf0ac79c6f73784 100644 (file)
@@ -365,3 +365,6 @@ parse_invalid_identifier_with_leading_number = expected identifier, found number
 
 parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
     .suggestion = replace `fn` with `impl` here
+
+parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
+    .suggestion = use `Fn` to refer to the trait
index ab9e8b6baae6ad4a3e30bbd92ff4bafe18e66e4c..bc37d91a7c6afd5cdcec34daa242be14e090bcae 100644 (file)
@@ -85,6 +85,7 @@ session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float lite
     .help = valid suffixes are `f32` and `f64`
 
 session_int_literal_too_large = integer literal is too large
+    .note = value exceeds limit of `{$limit}`
 
 session_invalid_int_literal_width = invalid width `{$width}` for integer literal
     .help = valid widths are 8, 16, 32, 64 and 128
index dee7a31ec2028287b06304fdb3b0b68f377a631e..cadd53fbd8356b3409ec98e7d9eaac9cfb54fcc4 100644 (file)
@@ -17,6 +17,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_target = { path = "../rustc_target" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 unicode-width = "0.1.4"
 termcolor = "1.0"
 annotate-snippets = "0.9"
index 585a54308c62e1c0bf07ab9c1478bd51ec0fca2c..e19a6fe0ee9bff2d5a0a5c28a7ace6c976c2fa9a 100644 (file)
@@ -365,12 +365,12 @@ pub fn span_labels(
         self
     }
 
-    pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
+    pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
         let before = self.span.clone();
         self.set_span(after);
         for span_label in before.span_labels() {
             if let Some(label) = span_label.label {
-                if span_label.is_primary {
+                if span_label.is_primary && keep_label {
                     self.span.push_span_label(after, label);
                 } else {
                     self.span.push_span_label(span_label.span, label);
index a2ed988643ff2a4ef2589ba99046d045725e250f..cbfee582d871f2c5925b0e8449e60dad19749212 100644 (file)
@@ -1,7 +1,7 @@
 use crate::diagnostic::IntoDiagnosticArg;
 use crate::{
     Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
-    SubdiagnosticMessage,
+    ExplicitBug, SubdiagnosticMessage,
 };
 use crate::{Handler, Level, MultiSpan, StashKey};
 use rustc_lint_defs::Applicability;
@@ -12,6 +12,7 @@
 use std::fmt::{self, Debug};
 use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
+use std::panic;
 use std::thread::panicking;
 
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
@@ -308,6 +309,58 @@ fn make_diagnostic_builder(
     }
 }
 
+/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
+/// bug struct diagnostics.
+#[derive(Copy, Clone)]
+pub struct Bug;
+
+impl<'a> DiagnosticBuilder<'a, Bug> {
+    /// Convenience function for internal use, clients should use one of the
+    /// `struct_*` methods on [`Handler`].
+    #[track_caller]
+    pub(crate) fn new_bug(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
+        let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message);
+        Self::new_diagnostic_bug(handler, diagnostic)
+    }
+
+    /// Creates a new `DiagnosticBuilder` with an already constructed
+    /// diagnostic.
+    pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+        debug!("Created new diagnostic bug");
+        Self {
+            inner: DiagnosticBuilderInner {
+                state: DiagnosticBuilderState::Emittable(handler),
+                diagnostic: Box::new(diagnostic),
+            },
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl EmissionGuarantee for Bug {
+    fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+        match db.inner.state {
+            // First `.emit()` call, the `&Handler` is still available.
+            DiagnosticBuilderState::Emittable(handler) => {
+                db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+
+                handler.emit_diagnostic(&mut db.inner.diagnostic);
+            }
+            // `.emit()` was previously called, disallowed from repeating it.
+            DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+        }
+        // Then panic. No need to return the marker type.
+        panic::panic_any(ExplicitBug);
+    }
+
+    fn make_diagnostic_builder(
+        handler: &Handler,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, Self> {
+        DiagnosticBuilder::new_bug(handler, msg)
+    }
+}
+
 impl<'a> DiagnosticBuilder<'a, !> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
index 628cb90903feedebcfe049f7cfeef978e6f053e3..794b6efcc2b246674b452ad0f4e3aa3e120b2b6a 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
 use rustc_target::abi::TargetDataLayoutErrors;
 use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
+use rustc_type_ir as type_ir;
 use std::borrow::Cow;
 use std::fmt;
 use std::num::ParseIntError;
@@ -170,6 +171,12 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
+impl IntoDiagnosticArg for type_ir::FloatTy {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Borrowed(self.name_str()))
+    }
+}
+
 impl IntoDiagnosticArg for Level {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(Cow::Borrowed(match self {
index e2a0e436fd5e2677a9524066380a034907ef59b0..0ca200abe19fb381097e2386bcf408c0863135ef 100644 (file)
@@ -845,7 +845,10 @@ fn render_source_line(
         // 3 | |
         // 4 | | }
         //   | |_^ test
-        if let [ann] = &line.annotations[..] {
+        let mut buffer_ops = vec![];
+        let mut annotations = vec![];
+        let mut short_start = true;
+        for ann in &line.annotations {
             if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
                 if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
                     let style = if ann.is_primary {
@@ -853,10 +856,23 @@ fn render_source_line(
                     } else {
                         Style::UnderlineSecondary
                     };
-                    buffer.putc(line_offset, width_offset + depth - 1, '/', style);
-                    return vec![(depth, style)];
+                    annotations.push((depth, style));
+                    buffer_ops.push((line_offset, width_offset + depth - 1, '/', style));
+                } else {
+                    short_start = false;
+                    break;
                 }
+            } else if let AnnotationType::MultilineLine(_) = ann.annotation_type {
+            } else {
+                short_start = false;
+                break;
+            }
+        }
+        if short_start {
+            for (y, x, c, s) in buffer_ops {
+                buffer.putc(y, x, c, s);
             }
+            return annotations;
         }
 
         // We want to display like this:
index b03352d5fec6b9274f4944ab122743cb646e2215..b4d23e96f8f45ca06a991bbfac73fa5622a0be41 100644 (file)
 use rustc_span::HashStableContext;
 use rustc_span::{Loc, Span};
 
+use std::any::Any;
 use std::borrow::Cow;
+use std::fmt;
 use std::hash::Hash;
 use std::num::NonZeroUsize;
 use std::panic;
 use std::path::Path;
-use std::{error, fmt};
 
 use termcolor::{Color, ColorSpec};
 
@@ -361,16 +362,11 @@ fn push_trailing(
 
 /// Signifies that the compiler died with an explicit call to `.bug`
 /// or `.span_bug` rather than a failed assertion, etc.
-#[derive(Copy, Clone, Debug)]
 pub struct ExplicitBug;
 
-impl fmt::Display for ExplicitBug {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "parser internal bug")
-    }
-}
-
-impl error::Error for ExplicitBug {}
+/// Signifies that the compiler died with an explicit call to `.delay_good_path_bug`
+/// rather than a failed assertion, etc.
+pub struct GoodPathBug;
 
 pub use diagnostic::{
     AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
@@ -473,10 +469,12 @@ pub enum StashKey {
     CallAssocMethod,
 }
 
-fn default_track_diagnostic(_: &Diagnostic) {}
+fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
+    (*f)(d)
+}
 
-pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
-    AtomicRef::new(&(default_track_diagnostic as fn(&_)));
+pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> =
+    AtomicRef::new(&(default_track_diagnostic as _));
 
 #[derive(Copy, Clone, Default)]
 pub struct HandlerFlags {
@@ -507,7 +505,11 @@ fn drop(&mut self) {
 
         if !self.has_errors() {
             let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
-            self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+            self.flush_delayed(
+                bugs,
+                "no errors encountered even though `delay_span_bug` issued",
+                ExplicitBug,
+            );
         }
 
         // FIXME(eddyb) this explains what `delayed_good_path_bugs` are!
@@ -520,6 +522,7 @@ fn drop(&mut self) {
             self.flush_delayed(
                 bugs.into_iter().map(DelayedDiagnostic::decorate),
                 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
+                GoodPathBug,
             );
         }
 
@@ -653,17 +656,19 @@ pub fn reset_err_count(&self) {
     /// Retrieve a stashed diagnostic with `steal_diagnostic`.
     pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
         let mut inner = self.inner.borrow_mut();
-        inner.stash((span, key), diag);
+        inner.stash((span.with_parent(None), key), diag);
     }
 
     /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
     pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
         let mut inner = self.inner.borrow_mut();
-        inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+        inner
+            .steal((span.with_parent(None), key))
+            .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
     }
 
     pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
-        self.inner.borrow().stashed_diagnostics.get(&(span, key)).is_some()
+        self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
     }
 
     /// Emit all stashed diagnostics.
@@ -973,6 +978,7 @@ pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMess
         self.inner.borrow_mut().span_bug(span, msg)
     }
 
+    /// For documentation on this, see `Session::delay_span_bug`.
     #[track_caller]
     pub fn delay_span_bug(
         &self,
@@ -1127,6 +1133,20 @@ pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
         self.create_fatal(fatal).emit()
     }
 
+    pub fn create_bug<'a>(
+        &'a self,
+        bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
+    ) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> {
+        bug.into_diagnostic(self)
+    }
+
+    pub fn emit_bug<'a>(
+        &'a self,
+        bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
+    ) -> diagnostic_builder::Bug {
+        self.create_bug(bug).emit()
+    }
+
     fn emit_diag_at_span(
         &self,
         mut diag: Diagnostic,
@@ -1203,7 +1223,11 @@ pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
     pub fn flush_delayed(&self) {
         let mut inner = self.inner.lock();
         let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new());
-        inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+        inner.flush_delayed(
+            bugs,
+            "no errors encountered even though `delay_span_bug` issued",
+            ExplicitBug,
+        );
     }
 }
 
@@ -1288,67 +1312,69 @@ fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaran
             && !diagnostic.is_force_warn()
         {
             if diagnostic.has_future_breakage() {
-                (*TRACK_DIAGNOSTICS)(diagnostic);
+                (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
             }
             return None;
         }
 
-        (*TRACK_DIAGNOSTICS)(diagnostic);
-
         if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
+            (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
             return None;
         }
 
-        if let Some(ref code) = diagnostic.code {
-            self.emitted_diagnostic_codes.insert(code.clone());
-        }
-
-        let already_emitted = |this: &mut Self| {
-            let mut hasher = StableHasher::new();
-            diagnostic.hash(&mut hasher);
-            let diagnostic_hash = hasher.finish();
-            !this.emitted_diagnostics.insert(diagnostic_hash)
-        };
+        let mut guaranteed = None;
+        (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| {
+            if let Some(ref code) = diagnostic.code {
+                self.emitted_diagnostic_codes.insert(code.clone());
+            }
 
-        // Only emit the diagnostic if we've been asked to deduplicate or
-        // haven't already emitted an equivalent diagnostic.
-        if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
-            debug!(?diagnostic);
-            debug!(?self.emitted_diagnostics);
-            let already_emitted_sub = |sub: &mut SubDiagnostic| {
-                debug!(?sub);
-                if sub.level != Level::OnceNote {
-                    return false;
-                }
+            let already_emitted = |this: &mut Self| {
                 let mut hasher = StableHasher::new();
-                sub.hash(&mut hasher);
+                diagnostic.hash(&mut hasher);
                 let diagnostic_hash = hasher.finish();
-                debug!(?diagnostic_hash);
-                !self.emitted_diagnostics.insert(diagnostic_hash)
+                !this.emitted_diagnostics.insert(diagnostic_hash)
             };
 
-            diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
-
-            self.emitter.emit_diagnostic(diagnostic);
-            if diagnostic.is_error() {
-                self.deduplicated_err_count += 1;
-            } else if let Warning(_) = diagnostic.level {
-                self.deduplicated_warn_count += 1;
+            // Only emit the diagnostic if we've been asked to deduplicate or
+            // haven't already emitted an equivalent diagnostic.
+            if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
+                debug!(?diagnostic);
+                debug!(?self.emitted_diagnostics);
+                let already_emitted_sub = |sub: &mut SubDiagnostic| {
+                    debug!(?sub);
+                    if sub.level != Level::OnceNote {
+                        return false;
+                    }
+                    let mut hasher = StableHasher::new();
+                    sub.hash(&mut hasher);
+                    let diagnostic_hash = hasher.finish();
+                    debug!(?diagnostic_hash);
+                    !self.emitted_diagnostics.insert(diagnostic_hash)
+                };
+
+                diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
+
+                self.emitter.emit_diagnostic(diagnostic);
+                if diagnostic.is_error() {
+                    self.deduplicated_err_count += 1;
+                } else if let Warning(_) = diagnostic.level {
+                    self.deduplicated_warn_count += 1;
+                }
             }
-        }
-        if diagnostic.is_error() {
-            if matches!(diagnostic.level, Level::Error { lint: true }) {
-                self.bump_lint_err_count();
+            if diagnostic.is_error() {
+                if matches!(diagnostic.level, Level::Error { lint: true }) {
+                    self.bump_lint_err_count();
+                } else {
+                    self.bump_err_count();
+                }
+
+                guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
             } else {
-                self.bump_err_count();
+                self.bump_warn_count();
             }
+        });
 
-            Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
-        } else {
-            self.bump_warn_count();
-
-            None
-        }
+        guaranteed
     }
 
     fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
@@ -1518,6 +1544,7 @@ fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>)
         self.emit_diagnostic(diag.set_span(sp));
     }
 
+    /// For documentation on this, see `Session::delay_span_bug`.
     #[track_caller]
     fn delay_span_bug(
         &mut self,
@@ -1580,6 +1607,7 @@ fn flush_delayed(
         &mut self,
         bugs: impl IntoIterator<Item = Diagnostic>,
         explanation: impl Into<DiagnosticMessage> + Copy,
+        panic_with: impl Any + Send + 'static,
     ) {
         let mut no_bugs = true;
         for mut bug in bugs {
@@ -1607,7 +1635,7 @@ fn flush_delayed(
 
         // Panic with `ExplicitBug` to avoid "unexpected panic" messages.
         if !no_bugs {
-            panic::panic_any(ExplicitBug);
+            panic::panic_any(panic_with);
         }
     }
 
index ef50efb81253fccd1c224c92f9a61e7d34b9471c..93b3af4ab973df72f3577c846ab34511cec49adf 100644 (file)
@@ -87,14 +87,14 @@ pub fn const_ident(&self, span: Span, ident: Ident) -> ast::AnonConst {
         self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident)))
     }
 
-    pub fn ty_rptr(
+    pub fn ty_ref(
         &self,
         span: Span,
         ty: P<ast::Ty>,
         lifetime: Option<ast::Lifetime>,
         mutbl: ast::Mutability,
     ) -> P<ast::Ty> {
-        self.ty(span, ast::TyKind::Rptr(lifetime, self.ty_mt(ty, mutbl)))
+        self.ty(span, ast::TyKind::Ref(lifetime, self.ty_mt(ty, mutbl)))
     }
 
     pub fn ty_ptr(&self, span: Span, ty: P<ast::Ty>, mutbl: ast::Mutability) -> P<ast::Ty> {
@@ -626,7 +626,7 @@ pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
 
     // Builds `#[name = val]`.
     //
-    // Note: `span` is used for both the identifer and the value.
+    // Note: `span` is used for both the identifier and the value.
     pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
         let g = &self.sess.parse_sess.attr_id_generator;
         attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
index e26c16dcd7ee7784e4597cddbb6f073c9ea56657..5d47c1ed363fbf0463ddde0118bba718d9ca10ec 100644 (file)
@@ -587,7 +587,7 @@ fn collect_invocations(
                 .resolver
                 .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
 
-            if self.cx.sess.opts.unstable_opts.incremental_relative_spans {
+            if self.cx.sess.opts.incremental_relative_spans() {
                 for (invoc, _) in invocations.iter_mut() {
                     let expn_id = invoc.expansion_data.id;
                     let parent_def = self.cx.resolver.invocation_parent(expn_id);
index 197f056917f5de75171e64c73c238b82559b7315..f469b2daef5eb7cf767e6f272ea2d6c05dbbe29f 100644 (file)
@@ -43,7 +43,7 @@ pub(super) fn failed_to_match_macro<'cx>(
         return result;
     }
 
-    let Some((token, label, remaining_matcher)) = tracker.best_failure else {
+    let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else {
         return DummyResult::any(sp);
     };
 
@@ -95,12 +95,31 @@ struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
     cx: &'a mut ExtCtxt<'cx>,
     remaining_matcher: Option<&'matcher MatcherLoc>,
     /// Which arm's failure should we report? (the one furthest along)
-    best_failure: Option<(Token, &'static str, MatcherLoc)>,
+    best_failure: Option<BestFailure>,
     root_span: Span,
     result: Option<Box<dyn MacResult + 'cx>>,
 }
 
+struct BestFailure {
+    token: Token,
+    position_in_tokenstream: usize,
+    msg: &'static str,
+    remaining_matcher: MatcherLoc,
+}
+
+impl BestFailure {
+    fn is_better_position(&self, position: usize) -> bool {
+        position > self.position_in_tokenstream
+    }
+}
+
 impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
+    type Failure = (Token, usize, &'static str);
+
+    fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
+        (tok, position, msg)
+    }
+
     fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) {
         if self.remaining_matcher.is_none()
             || (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof)
@@ -109,7 +128,7 @@ fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc)
         }
     }
 
-    fn after_arm(&mut self, result: &NamedParseResult) {
+    fn after_arm(&mut self, result: &NamedParseResult<Self::Failure>) {
         match result {
             Success(_) => {
                 // Nonterminal parser recovery might turn failed matches into successful ones,
@@ -119,18 +138,25 @@ fn after_arm(&mut self, result: &NamedParseResult) {
                     "should not collect detailed info for successful macro match",
                 );
             }
-            Failure(token, msg) => match self.best_failure {
-                Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {}
-                _ => {
-                    self.best_failure = Some((
-                        token.clone(),
+            Failure((token, approx_position, msg)) => {
+                debug!(?token, ?msg, "a new failure of an arm");
+
+                if self
+                    .best_failure
+                    .as_ref()
+                    .map_or(true, |failure| failure.is_better_position(*approx_position))
+                {
+                    self.best_failure = Some(BestFailure {
+                        token: token.clone(),
+                        position_in_tokenstream: *approx_position,
                         msg,
-                        self.remaining_matcher
+                        remaining_matcher: self
+                            .remaining_matcher
                             .expect("must have collected matcher already")
                             .clone(),
-                    ))
+                    })
                 }
-            },
+            }
             Error(err_sp, msg) => {
                 let span = err_sp.substitute_dummy(self.root_span);
                 self.cx.struct_span_err(span, msg).emit();
@@ -155,6 +181,21 @@ fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
     }
 }
 
+/// Currently used by macro_rules! compilation to extract a little information from the `Failure` case.
+pub struct FailureForwarder;
+
+impl<'matcher> Tracker<'matcher> for FailureForwarder {
+    type Failure = (Token, usize, &'static str);
+
+    fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
+        (tok, position, msg)
+    }
+
+    fn description() -> &'static str {
+        "failure-forwarder"
+    }
+}
+
 pub(super) fn emit_frag_parse_err(
     mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>,
     parser: &Parser<'_>,
@@ -178,12 +219,12 @@ pub(super) fn emit_frag_parse_err(
         );
         if !e.span.is_dummy() {
             // early end of macro arm (#52866)
-            e.replace_span_with(parser.token.span.shrink_to_hi());
+            e.replace_span_with(parser.token.span.shrink_to_hi(), true);
         }
     }
     if e.span.is_dummy() {
         // Get around lack of span in error (#30128)
-        e.replace_span_with(site_span);
+        e.replace_span_with(site_span, true);
         if !parser.sess.source_map().is_imported(arm_span) {
             e.span_label(arm_span, "in this macro arm");
         }
index d161868edce778677f02f7526acb6addf0069bb8..2e199541b92b43c08f0387b84deef90e8275a2cd 100644 (file)
@@ -305,12 +305,13 @@ enum EofMatcherPositions {
 }
 
 /// Represents the possible results of an attempted parse.
-pub(crate) enum ParseResult<T> {
+pub(crate) enum ParseResult<T, F> {
     /// Parsed successfully.
     Success(T),
     /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
     /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
-    Failure(Token, &'static str),
+    /// The usize is the approximate position of the token in the input token stream.
+    Failure(F),
     /// Fatal error (malformed macro?). Abort compilation.
     Error(rustc_span::Span, String),
     ErrorReported(ErrorGuaranteed),
@@ -319,7 +320,7 @@ pub(crate) enum ParseResult<T> {
 /// A `ParseResult` where the `Success` variant contains a mapping of
 /// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
 /// of metavars to the token trees they bind to.
-pub(crate) type NamedParseResult = ParseResult<NamedMatches>;
+pub(crate) type NamedParseResult<F> = ParseResult<NamedMatches, F>;
 
 /// Contains a mapping of `MacroRulesNormalizedIdent`s to `NamedMatch`es.
 /// This represents the mapping of metavars to the token trees they bind to.
@@ -455,8 +456,9 @@ fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
         &mut self,
         matcher: &'matcher [MatcherLoc],
         token: &Token,
+        approx_position: usize,
         track: &mut T,
-    ) -> Option<NamedParseResult> {
+    ) -> Option<NamedParseResult<T::Failure>> {
         // Matcher positions that would be valid if the macro invocation was over now. Only
         // modified if `token == Eof`.
         let mut eof_mps = EofMatcherPositions::None;
@@ -593,13 +595,14 @@ fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
                 EofMatcherPositions::Multiple => {
                     Error(token.span, "ambiguity: multiple successful parses".to_string())
                 }
-                EofMatcherPositions::None => Failure(
+                EofMatcherPositions::None => Failure(T::build_failure(
                     Token::new(
                         token::Eof,
                         if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
                     ),
+                    approx_position,
                     "missing tokens in macro arguments",
-                ),
+                )),
             })
         } else {
             None
@@ -612,7 +615,7 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
         parser: &mut Cow<'_, Parser<'_>>,
         matcher: &'matcher [MatcherLoc],
         track: &mut T,
-    ) -> NamedParseResult {
+    ) -> NamedParseResult<T::Failure> {
         // A queue of possible matcher positions. We initialize it with the matcher position in
         // which the "dot" is before the first token of the first token tree in `matcher`.
         // `parse_tt_inner` then processes all of these possible matcher positions and produces
@@ -627,7 +630,12 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
 
             // Process `cur_mps` until either we have finished the input or we need to get some
             // parsing from the black-box parser done.
-            let res = self.parse_tt_inner(matcher, &parser.token, track);
+            let res = self.parse_tt_inner(
+                matcher,
+                &parser.token,
+                parser.approx_token_stream_pos(),
+                track,
+            );
             if let Some(res) = res {
                 return res;
             }
@@ -640,10 +648,11 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
                 (0, 0) => {
                     // There are no possible next positions AND we aren't waiting for the black-box
                     // parser: syntax error.
-                    return Failure(
+                    return Failure(T::build_failure(
                         parser.token.clone(),
+                        parser.approx_token_stream_pos(),
                         "no rules expected this token in macro call",
-                    );
+                    ));
                 }
 
                 (_, 0) => {
@@ -702,11 +711,11 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
         }
     }
 
-    fn ambiguity_error(
+    fn ambiguity_error<F>(
         &self,
         matcher: &[MatcherLoc],
         token_span: rustc_span::Span,
-    ) -> NamedParseResult {
+    ) -> NamedParseResult<F> {
         let nts = self
             .bb_mps
             .iter()
@@ -732,11 +741,11 @@ fn ambiguity_error(
         )
     }
 
-    fn nameize<I: Iterator<Item = NamedMatch>>(
+    fn nameize<I: Iterator<Item = NamedMatch>, F>(
         &self,
         matcher: &[MatcherLoc],
         mut res: I,
-    ) -> NamedParseResult {
+    ) -> NamedParseResult<F> {
         // Make that each metavar has _exactly one_ binding. If so, insert the binding into the
         // `NamedParseResult`. Otherwise, it's an error.
         let mut ret_val = FxHashMap::default();
index 3e6bc81f67232f74b5df6b0809a9bd17b46981ec..c0489f686336b2747c9252500425e451561a83b6 100644 (file)
@@ -141,31 +141,40 @@ fn trace_macros_note(cx_expansions: &mut FxIndexMap<Span, Vec<String>>, sp: Span
 }
 
 pub(super) trait Tracker<'matcher> {
+    /// The contents of `ParseResult::Failure`.
+    type Failure;
+
+    /// Arm failed to match. If the token is `token::Eof`, it indicates an unexpected
+    /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
+    /// The usize is the approximate position of the token in the input token stream.
+    fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure;
+
     /// This is called before trying to match next MatcherLoc on the current token.
-    fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc);
+    fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {}
 
     /// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
     /// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`).
-    fn after_arm(&mut self, result: &NamedParseResult);
+    fn after_arm(&mut self, _result: &NamedParseResult<Self::Failure>) {}
 
     /// For tracing.
     fn description() -> &'static str;
 
-    fn recovery() -> Recovery;
+    fn recovery() -> Recovery {
+        Recovery::Forbidden
+    }
 }
 
 /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
 pub(super) struct NoopTracker;
 
 impl<'matcher> Tracker<'matcher> for NoopTracker {
-    fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {}
-    fn after_arm(&mut self, _: &NamedParseResult) {}
+    type Failure = ();
+
+    fn build_failure(_tok: Token, _position: usize, _msg: &'static str) -> Self::Failure {}
+
     fn description() -> &'static str {
         "none"
     }
-    fn recovery() -> Recovery {
-        Recovery::Forbidden
-    }
 }
 
 /// Expands the rules based macro defined by `lhses` and `rhses` for a given
@@ -326,7 +335,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
 
                 return Ok((i, named_matches));
             }
-            Failure(_, _) => {
+            Failure(_) => {
                 trace!("Failed to match arm, trying the next one");
                 // Try the next arm.
             }
@@ -381,11 +390,13 @@ pub fn compile_declarative_macro(
     let rhs_nm = Ident::new(sym::rhs, def.span);
     let tt_spec = Some(NonterminalKind::TT);
 
-    // Parse the macro_rules! invocation
-    let (macro_rules, body) = match &def.kind {
-        ast::ItemKind::MacroDef(def) => (def.macro_rules, def.body.tokens.clone()),
+    let macro_def = match &def.kind {
+        ast::ItemKind::MacroDef(def) => def,
         _ => unreachable!(),
     };
+    let macro_rules = macro_def.macro_rules;
+
+    // Parse the macro_rules! invocation
 
     // The pattern that macro_rules matches.
     // The grammar for macro_rules! is:
@@ -426,13 +437,32 @@ pub fn compile_declarative_macro(
     // Convert it into `MatcherLoc` form.
     let argument_gram = mbe::macro_parser::compute_locs(&argument_gram);
 
-    let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
+    let create_parser = || {
+        let body = macro_def.body.tokens.clone();
+        Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS)
+    };
+
+    let parser = create_parser();
     let mut tt_parser =
         TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
     let argument_map =
         match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
             Success(m) => m,
-            Failure(token, msg) => {
+            Failure(()) => {
+                // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it with another one
+                // that gives us the information we need.
+                // For this we need to reclone the macro body as the previous parser consumed it.
+                let retry_parser = create_parser();
+
+                let parse_result = tt_parser.parse_tt(
+                    &mut Cow::Owned(retry_parser),
+                    &argument_gram,
+                    &mut diagnostics::FailureForwarder,
+                );
+                let Failure((token, _, msg)) = parse_result else {
+                    unreachable!("matcher returned something other than Failure after retry");
+                };
+
                 let s = parse_failure_msg(&token);
                 let sp = token.span.substitute_dummy(def.span);
                 let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
index e5348039edd62c396847e0f581e14846566ce648..e2f30fb89b91e9b3dd12943a7741fa9e6d9a1ade 100644 (file)
@@ -194,7 +194,7 @@ macro_rules! declare_features {
     /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
     (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
     /// Allows `#[instruction_set(_)]` attribute.
-    (accepted, isa_attribute, "CURRENT_RUSTC_VERSION", Some(74727), None),
+    (accepted, isa_attribute, "1.67.0", Some(74727), None),
     /// Allows some increased flexibility in the name resolution rules,
     /// especially around globs and shadowing (RFC 1560).
     (accepted, item_like_imports, "1.15.0", Some(35120), None),
@@ -240,7 +240,7 @@ macro_rules! declare_features {
     /// Allows specifying the bundle link modifier
     (accepted, native_link_modifiers_bundle, "1.63.0", Some(81490), None),
     /// Allows specifying the verbatim link modifier
-    (accepted, native_link_modifiers_verbatim, "CURRENT_RUSTC_VERSION", Some(81490), None),
+    (accepted, native_link_modifiers_verbatim, "1.67.0", Some(81490), None),
     /// Allows specifying the whole-archive link modifier
     (accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None),
     /// Allows using non lexical lifetimes (RFC 2094).
index a616dd70f8e6ddb2e216ce73a9e97dde707f75a4..beade4d44da84e6f4bb7610cf59e4c356fa51b85 100644 (file)
@@ -383,7 +383,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `#[doc(masked)]`.
     (active, doc_masked, "1.21.0", Some(44027), None),
     /// Allows `dyn* Trait` objects.
-    (incomplete, dyn_star, "1.65.0", Some(91611), None),
+    (incomplete, dyn_star, "1.65.0", Some(102425), None),
     /// Allows `X..Y` patterns.
     (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
@@ -418,7 +418,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
     (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
     /// Allows referencing `Self` and projections in impl-trait.
-    (active, impl_trait_projections, "CURRENT_RUSTC_VERSION", Some(103532), None),
+    (active, impl_trait_projections, "1.67.0", Some(103532), None),
     /// Allows using imported `main` function
     (active, imported_main, "1.53.0", Some(28937), None),
     /// Allows associated types in inherent impls.
@@ -505,7 +505,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows lints part of the strict provenance effort.
     (active, strict_provenance, "1.61.0", Some(95228), None),
     /// Allows string patterns to dereference values to match them.
-    (active, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None),
+    (active, string_deref_patterns, "1.67.0", Some(87121), None),
     /// Allows the use of `#[target_feature]` on safe functions.
     (active, target_feature_11, "1.45.0", Some(69098), None),
     /// Allows using `#[thread_local]` on `static` items.
index 6d8e78a0f185dc6a16c577b6bb2a6c386f51389a..ad85231860d2de31a33af07eaf7a67bb163eedb5 100644 (file)
@@ -70,7 +70,7 @@ impl std::fmt::Debug for AttributeGate {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match *self {
             Self::Gated(ref stab, name, expl, _) => {
-                write!(fmt, "Gated({:?}, {}, {})", stab, name, expl)
+                write!(fmt, "Gated({stab:?}, {name}, {expl})")
             }
             Self::Ungated => write!(fmt, "Ungated"),
         }
index bdaa0ee88eba19792cd89fdd7d5104ce271fdfe9..8e2a13a6c0ab1deed02aecbd473868ad1b65cf4e 100644 (file)
@@ -120,7 +120,7 @@ fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
             .find(|t| t.name == feature);
         match found {
             Some(found) => found.issue,
-            None => panic!("feature `{}` is not declared anywhere", feature),
+            None => panic!("feature `{feature}` is not declared anywhere"),
         }
     }
 }
index 434f0a53b7866aed46efe8e4668653842cac157e..b70a55e89533524bf82f017529f7fb536d1811df 100644 (file)
@@ -516,7 +516,7 @@ pub fn to_dot_string(&self) -> String {
         match *self {
             LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
             EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
-            HtmlStr(ref s) => format!("<{}>", s),
+            HtmlStr(ref s) => format!("<{s}>"),
         }
     }
 
@@ -622,7 +622,7 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G, w: &mut W, options: &[RenderOption]
     if let Some(fontname) = options.iter().find_map(|option| {
         if let RenderOption::Fontname(fontname) = option { Some(fontname) } else { None }
     }) {
-        font = format!(r#"fontname="{}""#, fontname);
+        font = format!(r#"fontname="{fontname}""#);
         graph_attrs.push(&font[..]);
         content_attrs.push(&font[..]);
     }
@@ -635,8 +635,8 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G, w: &mut W, options: &[RenderOption]
     if !(graph_attrs.is_empty() && content_attrs.is_empty()) {
         writeln!(w, r#"    graph[{}];"#, graph_attrs.join(" "))?;
         let content_attrs_str = content_attrs.join(" ");
-        writeln!(w, r#"    node[{}];"#, content_attrs_str)?;
-        writeln!(w, r#"    edge[{}];"#, content_attrs_str)?;
+        writeln!(w, r#"    node[{content_attrs_str}];"#)?;
+        writeln!(w, r#"    edge[{content_attrs_str}];"#)?;
     }
 
     let mut text = Vec::new();
@@ -649,7 +649,7 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G, w: &mut W, options: &[RenderOption]
         write!(text, "{}", id.as_slice()).unwrap();
 
         if !options.contains(&RenderOption::NoNodeLabels) {
-            write!(text, "[label={}]", escaped).unwrap();
+            write!(text, "[label={escaped}]").unwrap();
         }
 
         let style = g.node_style(n);
@@ -678,7 +678,7 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G, w: &mut W, options: &[RenderOption]
         write!(text, "{} -> {}", source_id.as_slice(), target_id.as_slice()).unwrap();
 
         if !options.contains(&RenderOption::NoEdgeLabels) {
-            write!(text, "[label={}]", escaped_label).unwrap();
+            write!(text, "[label={escaped_label}]").unwrap();
         }
 
         let style = g.edge_style(e);
index 149cf4ece37d154613cd4bc44245ca60f2f73cd6..921039797869feca60ee20aee3677e578998b757 100644 (file)
@@ -597,8 +597,7 @@ pub fn def_id(&self) -> DefId
     where
         Id: Debug,
     {
-        self.opt_def_id()
-            .unwrap_or_else(|| panic!("attempted .def_id() on invalid res: {:?}", self))
+        self.opt_def_id().unwrap_or_else(|| panic!("attempted .def_id() on invalid res: {self:?}"))
     }
 
     /// Return `Some(..)` with the `DefId` of this `Res` if it has a ID, else `None`.
index dd37efb6983b429e5db6869e707662775ec444c3..21cf214e47c50d13535d11c2847b5ed4bce82e2a 100644 (file)
@@ -53,9 +53,8 @@ fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
             //
             // See the documentation for DefPathHash for more information.
             panic!(
-                "found DefPathHash collision between {:?} and {:?}. \
-                    Compilation cannot continue.",
-                def_path1, def_path2
+                "found DefPathHash collision between {def_path1:?} and {def_path2:?}. \
+                    Compilation cannot continue."
             );
         }
 
@@ -224,7 +223,7 @@ pub fn to_string_no_crate_verbose(&self) -> String {
         let mut s = String::with_capacity(self.data.len() * 16);
 
         for component in &self.data {
-            write!(s, "::{}", component).unwrap();
+            write!(s, "::{component}").unwrap();
         }
 
         s
@@ -240,7 +239,7 @@ pub fn to_filename_friendly_no_crate(&self) -> String {
         for component in &self.data {
             s.extend(opt_delimiter);
             opt_delimiter = Some('-');
-            write!(s, "{}", component).unwrap();
+            write!(s, "{component}").unwrap();
         }
 
         s
@@ -433,7 +432,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.name() {
             DefPathDataName::Named(name) => f.write_str(name.as_str()),
             // FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc
-            DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace),
+            DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"),
         }
     }
 }
index 91825c29258ac10bd345aedbd19fcf35faa1da72..bc897ed8112e59e5659dde99527a1452abae6be2 100644 (file)
@@ -854,7 +854,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 &self
                     .nodes
                     .iter_enumerated()
-                    .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent)))
+                    .map(|(id, parented_node)| {
+                        let parented_node = parented_node.as_ref().map(|node| node.parent);
+
+                        debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})"))
+                    })
                     .collect::<Vec<_>>(),
             )
             .field("bodies", &self.bodies)
@@ -2431,7 +2435,7 @@ pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
 
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
-        while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
             final_ty = ty;
         }
         final_ty
@@ -2588,7 +2592,7 @@ pub enum TyKind<'hir> {
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
-    Rptr(&'hir Lifetime, MutTy<'hir>),
+    Ref(&'hir Lifetime, MutTy<'hir>),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(&'hir BareFnTy<'hir>),
     /// The never type (`!`).
@@ -3456,7 +3460,7 @@ impl<'hir> Node<'hir> {
     /// ```ignore (illustrative)
     /// ctor
     ///     .ctor_hir_id()
-    ///     .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
+    ///     .and_then(|ctor_id| tcx.hir().find_parent(ctor_id))
     ///     .and_then(|parent| parent.ident())
     /// ```
     pub fn ident(&self) -> Option<Ident> {
@@ -3609,16 +3613,19 @@ mod size_asserts {
     static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
-    // tidy-alphabetical-end
-    // FIXME: move the tidy directive to the end after the next bootstrap bump
-    #[cfg(bootstrap)]
-    static_assert_size!(TraitItem<'_>, 88);
-    #[cfg(not(bootstrap))]
     static_assert_size!(TraitItem<'_>, 80);
-    #[cfg(bootstrap)]
-    static_assert_size!(TraitItemKind<'_>, 48);
-    #[cfg(not(bootstrap))]
     static_assert_size!(TraitItemKind<'_>, 40);
     static_assert_size!(Ty<'_>, 48);
     static_assert_size!(TyKind<'_>, 32);
+    // tidy-alphabetical-end
+}
+
+fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
+    struct DebugFn<F>(F);
+    impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
+        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+            (self.0)(fmt)
+        }
+    }
+    DebugFn(f)
 }
index 03bcaa6946825baac7073958262ddd75f7bd3bf2..3b4add0cf4d40295f1de0d41e3cf8a7ee199fc76 100644 (file)
@@ -1,14 +1,21 @@
 use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt;
+use std::fmt::{self, Debug};
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable)]
 pub struct OwnerId {
     pub def_id: LocalDefId,
 }
 
+impl Debug for OwnerId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: DefId(0:1 ~ aa[7697]::{use#0})
+        Debug::fmt(&self.def_id, f)
+    }
+}
+
 impl From<OwnerId> for HirId {
     fn from(owner: OwnerId) -> HirId {
         HirId { owner, local_id: ItemLocalId::from_u32(0) }
@@ -60,7 +67,7 @@ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
 /// the `local_id` part of the `HirId` changing, which is a very useful property in
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub struct HirId {
@@ -68,6 +75,14 @@ pub struct HirId {
     pub local_id: ItemLocalId,
 }
 
+impl Debug for HirId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+        // Don't use debug_tuple to always keep this on one line.
+        write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+    }
+}
+
 impl HirId {
     /// Signal local id which should never be used.
     pub const INVALID: HirId =
@@ -104,7 +119,7 @@ pub fn index(self) -> (usize, usize) {
 
 impl fmt::Display for HirId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self)
+        write!(f, "{self:?}")
     }
 }
 
index 938ace2c785bbf1aa7d2bd9cfd50a5bf98146979..6c475b659eba0a87aaf65d8959dae479bbcac42c 100644 (file)
@@ -809,7 +809,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
     match typ.kind {
         TyKind::Slice(ref ty) => visitor.visit_ty(ty),
         TyKind::Ptr(ref mutable_type) => visitor.visit_ty(mutable_type.ty),
-        TyKind::Rptr(ref lifetime, ref mutable_type) => {
+        TyKind::Ref(ref lifetime, ref mutable_type) => {
             visitor.visit_lifetime(lifetime);
             visitor.visit_ty(mutable_type.ty)
         }
index 6f0c5d36a5f539c63e6365e493d51c846c5171c2..5a7957be318ea642a19f9753af3ab1106f43b010 100644 (file)
@@ -106,11 +106,12 @@ fn projected_ty_from_poly_trait_ref(
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Ty<'tcx>;
 
-    /// Normalize an associated type coming from the user.
-    ///
-    /// This should only be used by astconv. Use `FnCtxt::normalize`
-    /// or `ObligationCtxt::normalize` in downstream crates.
-    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
+    /// Returns `AdtDef` if `ty` is an ADT.
+    /// Note that `ty` might be a projection type that needs normalization.
+    /// This used to get the enum variants in scope of the type.
+    /// For example, `Self::A` could refer to an associated type
+    /// or to an enum variant depending on the result of this function.
+    fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>>;
 
     /// Invoked when we encounter an error from some prior pass
     /// (e.g., resolve) that is translated into a ty-error. This is
@@ -485,14 +486,7 @@ fn inferred_kind(
                                 // Avoid ICE #86756 when type error recovery goes awry.
                                 return tcx.ty_error().into();
                             }
-                            self.astconv
-                                .normalize_ty(
-                                    self.span,
-                                    tcx.at(self.span)
-                                        .bound_type_of(param.def_id)
-                                        .subst(tcx, substs),
-                                )
-                                .into()
+                            tcx.at(self.span).bound_type_of(param.def_id).subst(tcx, substs).into()
                         } else if infer_args {
                             self.astconv.ty_infer(Some(param), self.span).into()
                         } else {
@@ -682,7 +676,7 @@ fn instantiate_poly_trait_ref_inner(
             ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
 
         debug!(?poly_trait_ref, ?assoc_bindings);
-        bounds.trait_bounds.push((poly_trait_ref, span, constness));
+        bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
 
         let mut dup_bindings = FxHashMap::default();
         for binding in &assoc_bindings {
@@ -853,18 +847,19 @@ fn trait_defines_associated_const_named(&self, trait_def_id: DefId, assoc_name:
     }
 
     /// Sets `implicitly_sized` to true on `Bounds` if necessary
-    pub(crate) fn add_implicitly_sized<'hir>(
+    pub(crate) fn add_implicitly_sized(
         &self,
-        bounds: &mut Bounds<'hir>,
-        ast_bounds: &'hir [hir::GenericBound<'hir>],
-        self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
+        bounds: &mut Bounds<'tcx>,
+        self_ty: Ty<'tcx>,
+        ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+        self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
     ) {
         let tcx = self.tcx();
 
         // Try to find an unbound in bounds.
         let mut unbound = None;
-        let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
+        let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
             for ab in ast_bounds {
                 if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
                     if unbound.is_none() {
@@ -912,7 +907,7 @@ pub(crate) fn add_implicitly_sized<'hir>(
             // No lang item for `Sized`, so we can't add it as a bound.
             return;
         }
-        bounds.implicitly_sized = Some(span);
+        bounds.push_sized(tcx, self_ty, span);
     }
 
     /// This helper takes a *converted* parameter type (`param_ty`)
@@ -963,10 +958,14 @@ pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>
                 }
                 hir::GenericBound::Outlives(lifetime) => {
                     let region = self.ast_region_to_region(lifetime, None);
-                    bounds.region_bounds.push((
-                        ty::Binder::bind_with_vars(region, bound_vars),
+                    bounds.push_region_bound(
+                        self.tcx(),
+                        ty::Binder::bind_with_vars(
+                            ty::OutlivesPredicate(param_ty, region),
+                            bound_vars,
+                        ),
                         lifetime.ident.span,
-                    ));
+                    );
                 }
             }
         }
@@ -1199,17 +1198,26 @@ fn add_predicates_for_ast_type_binding(
                     (_, _) => {
                         let got = if let Some(_) = term.ty() { "type" } else { "constant" };
                         let expected = def_kind.descr(assoc_item_def_id);
-                        let reported = tcx
-                            .sess
-                            .struct_span_err(
+                        let mut err = tcx.sess.struct_span_err(
+                            binding.span,
+                            &format!("expected {expected} bound, found {got}"),
+                        );
+                        err.span_note(
+                            tcx.def_span(assoc_item_def_id),
+                            &format!("{expected} defined here"),
+                        );
+
+                        if let hir::def::DefKind::AssocConst = def_kind
+                          && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
+                          && tcx.features().associated_const_equality {
+                            err.span_suggestion(
                                 binding.span,
-                                &format!("expected {expected} bound, found {got}"),
-                            )
-                            .span_note(
-                                tcx.def_span(assoc_item_def_id),
-                                &format!("{expected} defined here"),
-                            )
-                            .emit();
+                                "if equating a const, try wrapping with braces",
+                                format!("{} = {{ const }}", binding.item_name),
+                                Applicability::HasPlaceholders,
+                            );
+                        }
+                        let reported = err.emit();
                         term = match def_kind {
                             hir::def::DefKind::AssocTy => {
                                 tcx.ty_error_with_guaranteed(reported).into()
@@ -1225,13 +1233,12 @@ fn add_predicates_for_ast_type_binding(
                         };
                     }
                 }
-                bounds.projection_bounds.push((
-                    projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
-                        projection_ty,
-                        term: term,
-                    }),
+                bounds.push_projection_bound(
+                    tcx,
+                    projection_ty
+                        .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
                     binding.span,
-                ));
+                );
             }
             ConvertedBindingKind::Constraint(ast_bounds) => {
                 // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
@@ -1254,13 +1261,13 @@ fn ast_path_to_ty(
         item_segment: &hir::PathSegment<'_>,
     ) -> Ty<'tcx> {
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        self.normalize_ty(span, self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs))
+        self.tcx().at(span).bound_type_of(did).subst(self.tcx(), substs)
     }
 
     fn conv_object_ty_poly_trait_ref(
         &self,
         span: Span,
-        trait_bounds: &[hir::PolyTraitRef<'_>],
+        hir_trait_bounds: &[hir::PolyTraitRef<'_>],
         lifetime: &hir::Lifetime,
         borrowed: bool,
         representation: DynKind,
@@ -1270,7 +1277,7 @@ fn conv_object_ty_poly_trait_ref(
         let mut bounds = Bounds::default();
         let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
-        for trait_bound in trait_bounds.iter().rev() {
+        for trait_bound in hir_trait_bounds.iter().rev() {
             if let GenericArgCountResult {
                 correct:
                     Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
@@ -1287,10 +1294,45 @@ fn conv_object_ty_poly_trait_ref(
             }
         }
 
+        let mut trait_bounds = vec![];
+        let mut projection_bounds = vec![];
+        for (pred, span) in bounds.predicates() {
+            let bound_pred = pred.kind();
+            match bound_pred.skip_binder() {
+                ty::PredicateKind::Clause(clause) => match clause {
+                    ty::Clause::Trait(trait_pred) => {
+                        assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+                        trait_bounds.push((
+                            bound_pred.rebind(trait_pred.trait_ref),
+                            span,
+                            trait_pred.constness,
+                        ));
+                    }
+                    ty::Clause::Projection(proj) => {
+                        projection_bounds.push((bound_pred.rebind(proj), span));
+                    }
+                    ty::Clause::TypeOutlives(_) => {
+                        // Do nothing, we deal with regions separately
+                    }
+                    ty::Clause::RegionOutlives(_) => bug!(),
+                },
+                ty::PredicateKind::WellFormed(_)
+                | ty::PredicateKind::ObjectSafe(_)
+                | ty::PredicateKind::ClosureKind(_, _, _)
+                | ty::PredicateKind::Subtype(_)
+                | ty::PredicateKind::Coerce(_)
+                | ty::PredicateKind::ConstEvaluatable(_)
+                | ty::PredicateKind::ConstEquate(_, _)
+                | ty::PredicateKind::TypeWellFormedFromEnv(_)
+                | ty::PredicateKind::Ambiguous => bug!(),
+            }
+        }
+
         // Expand trait aliases recursively and check that only one regular (non-auto) trait
         // is used and no 'maybe' bounds are used.
         let expanded_traits =
-            traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+            traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+
         let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
             .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
             .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
@@ -1327,8 +1369,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
         }
 
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            let trait_alias_span = bounds
-                .trait_bounds
+            let trait_alias_span = trait_bounds
                 .iter()
                 .map(|&(trait_ref, _, _)| trait_ref.def_id())
                 .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
@@ -1359,8 +1400,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
         // Use a `BTreeSet` to keep output in a more consistent order.
         let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
 
-        let regular_traits_refs_spans = bounds
-            .trait_bounds
+        let regular_traits_refs_spans = trait_bounds
             .into_iter()
             .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
@@ -1414,7 +1454,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
                         // the discussion in #56288 for alternatives.
                         if !references_self {
                             // Include projections defined on supertraits.
-                            bounds.projection_bounds.push((pred, span));
+                            projection_bounds.push((pred, span));
                         }
                     }
                     _ => (),
@@ -1422,7 +1462,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
             }
         }
 
-        for (projection_bound, _) in &bounds.projection_bounds {
+        for (projection_bound, _) in &projection_bounds {
             for def_ids in associated_types.values_mut() {
                 def_ids.remove(&projection_bound.projection_def_id());
             }
@@ -1431,7 +1471,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
         self.complain_about_missing_associated_types(
             associated_types,
             potential_assoc_types,
-            trait_bounds,
+            hir_trait_bounds,
         );
 
         // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
@@ -1473,7 +1513,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
                 let substs = tcx.intern_substs(&substs[..]);
 
                 let span = i.bottom().1;
-                let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
+                let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
                     hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
                         && hir_bound.span.contains(span)
                 });
@@ -1505,7 +1545,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
             })
         });
 
-        let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
+        let existential_projections = projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|mut b| {
                 assert_eq!(b.projection_ty.self_ty(), dummy_self);
 
@@ -1786,7 +1826,7 @@ fn one_bound_for_assoc_type<I>(
         Ok(bound)
     }
 
-    // Create a type from a path to an associated type.
+    // Create a type from a path to an associated type or to an enum variant.
     // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
     // and item_segment is the path segment for `D`. We return a type and a def for
     // the whole path.
@@ -1814,7 +1854,7 @@ pub fn associated_path_to_ty(
 
         // Check if we have an enum variant.
         let mut variant_resolution = None;
-        if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
+        if let Some(adt_def) = self.probe_adt(span, qself_ty) {
             if adt_def.is_enum() {
                 let variant_def = adt_def
                     .variants()
@@ -1916,6 +1956,10 @@ pub fn associated_path_to_ty(
                 let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
                     continue;
                 };
+                let ty::Adt(_, adt_substs) = qself_ty.kind() else {
+                    // FIXME(inherent_associated_types)
+                    bug!("unimplemented: non-adt self of inherent assoc ty");
+                };
                 let item_substs = self.create_substs_for_associated_item(
                     span,
                     assoc_ty_did,
@@ -1923,7 +1967,6 @@ pub fn associated_path_to_ty(
                     adt_substs,
                 );
                 let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
-                let ty = self.normalize_ty(span, ty);
                 return Ok((ty, DefKind::AssocTy, assoc_ty_did));
             }
         }
@@ -2020,7 +2063,6 @@ pub fn associated_path_to_ty(
         };
 
         let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
-        let ty = self.normalize_ty(span, ty);
 
         if let Some(variant_def_id) = variant_resolution {
             tcx.struct_span_lint_hir(
@@ -2156,7 +2198,7 @@ fn qpath_to_ty(
 
         debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
 
-        self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
+        tcx.mk_projection(item_def_id, item_substs)
     }
 
     pub fn prohibit_generics<'a>(
@@ -2273,6 +2315,7 @@ pub fn def_ids_for_value_path_segments(
         self_ty: Option<Ty<'tcx>>,
         kind: DefKind,
         def_id: DefId,
+        span: Span,
     ) -> Vec<PathSeg> {
         // We need to extract the type parameters supplied by the user in
         // the path `path`. Due to the current setup, this is a bit of a
@@ -2340,8 +2383,8 @@ pub fn def_ids_for_value_path_segments(
 
             // Case 2. Reference to a variant constructor.
             DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => {
-                let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
-                let (generics_def_id, index) = if let Some(adt_def) = adt_def {
+                let (generics_def_id, index) = if let Some(self_ty) = self_ty {
+                    let adt_def = self.probe_adt(span, self_ty).unwrap();
                     debug_assert!(adt_def.is_enum());
                     (adt_def.did(), last)
                 } else if last >= 1 && segments[last - 1].args.is_some() {
@@ -2417,7 +2460,7 @@ pub fn res_to_ty(
                     err.note("`impl Trait` types can't have type parameters");
                 });
                 let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
-                self.normalize_ty(span, tcx.mk_opaque(did, substs))
+                tcx.mk_opaque(did, substs)
             }
             Res::Def(
                 DefKind::Enum
@@ -2437,7 +2480,7 @@ pub fn res_to_ty(
                 assert_eq!(opt_self_ty, None);
 
                 let path_segs =
-                    self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
+                    self.def_ids_for_value_path_segments(path.segments, None, kind, def_id, span);
                 let generic_segs: FxHashSet<_> =
                     path_segs.iter().map(|PathSeg(_, index)| index).collect();
                 self.prohibit_generics(
@@ -2577,7 +2620,7 @@ pub fn res_to_ty(
                     }
                     tcx.ty_error_with_guaranteed(err.emit())
                 } else {
-                    self.normalize_ty(span, ty)
+                    ty
                 }
             }
             Res::Def(DefKind::AssocTy, def_id) => {
@@ -2657,7 +2700,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
             hir::TyKind::Ptr(ref mt) => {
                 tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
             }
-            hir::TyKind::Rptr(ref region, ref mt) => {
+            hir::TyKind::Ref(ref region, ref mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!(?r);
                 let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
@@ -2720,8 +2763,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     None,
                     ty::BoundConstness::NotConst,
                 );
-                EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
-                    .subst(tcx, substs)
+                EarlyBinder(tcx.at(span).type_of(def_id)).subst(tcx, substs)
             }
             hir::TyKind::Array(ref ty, ref length) => {
                 let length = match length {
@@ -2731,8 +2773,7 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     }
                 };
 
-                let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
-                self.normalize_ty(ast_ty.span, array_ty)
+                tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length))
             }
             hir::TyKind::Typeof(ref e) => {
                 let ty_erased = tcx.type_of(e.def_id);
@@ -2936,7 +2977,7 @@ fn suggest_trait_fn_ty_for_impl_fn_infer(
         let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
             hir.get(fn_hir_id) else { return None };
         let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
-                hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
+                hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") };
 
         let trait_ref = self.instantiate_mono_trait_ref(
             i.of_trait.as_ref()?,
index 3e3544ce666e39e6b296e4b8d9ad2ecc255288e2..0880c8c15f2e0592ead59099fd535d25fc645c7d 100644 (file)
@@ -1,6 +1,7 @@
 //! Bounds are restrictions applied to some types after they've been converted into the
 //! `ty` form from the HIR.
 
+use rustc_hir::LangItem;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
 
 ///           ^^^^^^^^^ bounding the type parameter `T`
 ///
 /// impl dyn Bar + Baz
-///          ^^^^^^^^^ bounding the forgotten dynamic type
+///          ^^^^^^^^^ bounding the type-erased dynamic type
 /// ```
 ///
 /// Our representation is a bit mixed here -- in some cases, we
 /// include the self type (e.g., `trait_bounds`) but in others we do not
 #[derive(Default, PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
-    /// A list of region bounds on the (implicit) self type. So if you
-    /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
-    /// the `T` is not explicitly included).
-    pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>,
-
-    /// A list of trait bounds. So if you had `T: Debug` this would be
-    /// `T: Debug`. Note that the self-type is explicit here.
-    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
-
-    /// A list of projection equality bounds. So if you had `T:
-    /// Iterator<Item = u32>` this would include `<T as
-    /// Iterator>::Item => u32`. Note that the self-type is explicit
-    /// here.
-    pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
-
-    /// `Some` if there is *no* `?Sized` predicate. The `span`
-    /// is the location in the source of the `T` declaration which can
-    /// be cited as the source of the `T: Sized` requirement.
-    pub implicitly_sized: Option<Span>,
+    pub predicates: Vec<(ty::Predicate<'tcx>, Span)>,
 }
 
 impl<'tcx> Bounds<'tcx> {
-    /// Converts a bounds list into a flat set of predicates (like
-    /// where-clauses). Because some of our bounds listings (e.g.,
-    /// regions) don't include the self-type, you must supply the
-    /// self-type here (the `param_ty` parameter).
-    pub fn predicates<'out, 's>(
-        &'s self,
+    pub fn push_region_bound(
+        &mut self,
         tcx: TyCtxt<'tcx>,
-        param_ty: Ty<'tcx>,
-        // the output must live shorter than the duration of the borrow of self and 'tcx.
-    ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
-    where
-        'tcx: 'out,
-        's: 'out,
-    {
-        // If it could be sized, and is, add the `Sized` predicate.
-        let sized_predicate = self.implicitly_sized.and_then(|span| {
-            // FIXME: use tcx.at(span).mk_trait_ref(LangItem::Sized) here? This may make no-core code harder to write.
-            let sized = tcx.lang_items().sized_trait()?;
-            let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized, [param_ty]));
-            Some((trait_ref.without_const().to_predicate(tcx), span))
-        });
+        region: ty::PolyTypeOutlivesPredicate<'tcx>,
+        span: Span,
+    ) {
+        self.predicates.push((region.to_predicate(tcx), span));
+    }
 
-        let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
-            let pred = region_bound
-                .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
-                .to_predicate(tcx);
-            (pred, span)
-        });
-        let trait_bounds =
-            self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
-                let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
-                (predicate, span)
-            });
-        let projection_bounds = self
-            .projection_bounds
-            .iter()
-            .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+    pub fn push_trait_bound(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        span: Span,
+        constness: ty::BoundConstness,
+    ) {
+        self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span));
+    }
+
+    pub fn push_projection_bound(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        projection: ty::PolyProjectionPredicate<'tcx>,
+        span: Span,
+    ) {
+        self.predicates.push((projection.to_predicate(tcx), span));
+    }
+
+    pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
+        let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
+        let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty]));
+        // Preferrable to put this obligation first, since we report better errors for sized ambiguity.
+        self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
+    }
 
-        sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
+    pub fn predicates(&self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + '_ {
+        self.predicates.iter().cloned()
     }
 }
index a714663741be72eaf7448eae77b05c45bf4f8aec..ef563360c4cebb8d3e0265ead2be59430e5013d1 100644 (file)
@@ -1,8 +1,8 @@
 use crate::check::intrinsicck::InlineAsmCtxt;
 use crate::errors::LinkageType;
 
-use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_impl_method, compare_ty_impl};
+use super::compare_impl_item::check_type_bounds;
+use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
 use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -468,7 +468,7 @@ fn check_opaque_meets_bounds<'tcx>(
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias => {
             let outlives_environment = OutlivesEnvironment::new(param_env);
-            infcx.check_region_obligations_and_report_errors(
+            let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(
                 defining_use_anchor,
                 &outlives_environment,
             );
@@ -774,7 +774,7 @@ fn check_impl_items_against_trait<'tcx>(
         let impl_item_full = tcx.hir().impl_item(impl_item.id);
         match impl_item_full.kind {
             hir::ImplItemKind::Const(..) => {
-                let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
+                let _ = tcx.compare_impl_const((
                     impl_item.id.owner_id.def_id,
                     ty_impl_item.trait_item_def_id.unwrap(),
                 ));
@@ -791,7 +791,7 @@ fn check_impl_items_against_trait<'tcx>(
             }
             hir::ImplItemKind::Type(impl_ty) => {
                 let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                compare_ty_impl(
+                compare_impl_ty(
                     tcx,
                     &ty_impl_item,
                     impl_ty.span,
@@ -1060,10 +1060,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
 
     if adt.variants().len() != 1 {
         bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
-        if adt.variants().is_empty() {
-            // Don't bother checking the fields. No variants (and thus no fields) exist.
-            return;
-        }
+        // Don't bother checking the fields.
+        return;
     }
 
     // For each field, figure out if it's known to be a ZST and align(1), with "known"
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
new file mode 100644 (file)
index 0000000..b260b92
--- /dev/null
@@ -0,0 +1,2000 @@
+use super::potentially_plural_count;
+use crate::errors::LifetimesOrBoundsMismatchOnTrait;
+use hir::def_id::{DefId, LocalDefId};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit;
+use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::util;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::{
+    self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
+use rustc_span::Span;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
+use rustc_trait_selection::traits::{
+    self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
+};
+use std::iter;
+
+/// Checks that a method from an impl conforms to the signature of
+/// the same method as declared in the trait.
+///
+/// # Parameters
+///
+/// - `impl_m`: type of the method we are checking
+/// - `impl_m_span`: span to use for reporting errors
+/// - `trait_m`: the method in the trait
+/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
+pub(super) fn compare_impl_method<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    trait_m: &ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    trait_item_span: Option<Span>,
+) {
+    debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
+
+    let impl_m_span = tcx.def_span(impl_m.def_id);
+
+    if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
+        return;
+    }
+
+    if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
+        return;
+    }
+
+    if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
+        return;
+    }
+
+    if let Err(_) =
+        compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
+    {
+        return;
+    }
+
+    if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
+        return;
+    }
+
+    if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+        return;
+    }
+
+    if let Err(_) = compare_method_predicate_entailment(
+        tcx,
+        impl_m,
+        impl_m_span,
+        trait_m,
+        impl_trait_ref,
+        CheckImpliedWfMode::Check,
+    ) {
+        return;
+    }
+}
+
+/// This function is best explained by example. Consider a trait:
+///
+///     trait Trait<'t, T> {
+///         // `trait_m`
+///         fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
+///     }
+///
+/// And an impl:
+///
+///     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
+///          // `impl_m`
+///          fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
+///     }
+///
+/// We wish to decide if those two method types are compatible.
+/// For this we have to show that, assuming the bounds of the impl hold, the
+/// bounds of `trait_m` imply the bounds of `impl_m`.
+///
+/// We start out with `trait_to_impl_substs`, that maps the trait
+/// type parameters to impl type parameters. This is taken from the
+/// impl trait reference:
+///
+///     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+///
+/// We create a mapping `dummy_substs` that maps from the impl type
+/// parameters to fresh types and regions. For type parameters,
+/// this is the identity transform, but we could as well use any
+/// placeholder types. For regions, we convert from bound to free
+/// regions (Note: but only early-bound regions, i.e., those
+/// declared on the impl or used in type parameter bounds).
+///
+///     impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
+///
+/// Now we can apply `placeholder_substs` to the type of the impl method
+/// to yield a new function type in terms of our fresh, placeholder
+/// types:
+///
+///     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+///
+/// We now want to extract and substitute the type of the *trait*
+/// method and compare it. To do so, we must create a compound
+/// substitution by combining `trait_to_impl_substs` and
+/// `impl_to_placeholder_substs`, and also adding a mapping for the method
+/// type parameters. We extend the mapping to also include
+/// the method parameters.
+///
+///     trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+///
+/// Applying this to the trait method type yields:
+///
+///     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+///
+/// This type is also the same but the name of the bound region (`'a`
+/// vs `'b`).  However, the normal subtyping rules on fn types handle
+/// this kind of equivalency just fine.
+///
+/// We now use these substitutions to ensure that all declared bounds are
+/// satisfied by the implementation's method.
+///
+/// We do this by creating a parameter environment which contains a
+/// substitution corresponding to `impl_to_placeholder_substs`. We then build
+/// `trait_to_placeholder_substs` and use it to convert the predicates contained
+/// in the `trait_m` generics to the placeholder form.
+///
+/// Finally we register each of these predicates as an obligation and check that
+/// they hold.
+#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
+fn compare_method_predicate_entailment<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    impl_m_span: Span,
+    trait_m: &ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    check_implied_wf: CheckImpliedWfMode,
+) -> Result<(), ErrorGuaranteed> {
+    let trait_to_impl_substs = impl_trait_ref.substs;
+
+    // This node-id should be used for the `body_id` field on each
+    // `ObligationCause` (and the `FnCtxt`).
+    //
+    // FIXME(@lcnr): remove that after removing `cause.body_id` from
+    // obligations.
+    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+    let cause = ObligationCause::new(
+        impl_m_span,
+        impl_m_hir_id,
+        ObligationCauseCode::CompareImplItemObligation {
+            impl_item_def_id: impl_m.def_id.expect_local(),
+            trait_item_def_id: trait_m.def_id,
+            kind: impl_m.kind,
+        },
+    );
+
+    // Create mapping from impl to placeholder.
+    let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
+
+    // Create mapping from trait to placeholder.
+    let trait_to_placeholder_substs =
+        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
+    debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
+
+    let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
+    let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
+
+    // Check region bounds.
+    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
+
+    // Create obligations for each predicate declared by the impl
+    // definition in the context of the trait's parameter
+    // environment. We can't just use `impl_env.caller_bounds`,
+    // however, because we want to replace all late-bound regions with
+    // region variables.
+    let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
+    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
+
+    debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
+
+    // This is the only tricky bit of the new way we check implementation methods
+    // We need to build a set of predicates where only the method-level bounds
+    // are from the trait and we assume all other bounds from the implementation
+    // to be previously satisfied.
+    //
+    // We then register the obligations from the impl_m and check to see
+    // if all constraints hold.
+    hybrid_preds
+        .predicates
+        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
+
+    // Construct trait parameter environment and then shift it into the placeholder viewpoint.
+    // The key step here is to update the caller_bounds's predicates to be
+    // the new hybrid bounds we computed.
+    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
+    let param_env = ty::ParamEnv::new(
+        tcx.intern_predicates(&hybrid_preds.predicates),
+        Reveal::UserFacing,
+        hir::Constness::NotConst,
+    );
+    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
+
+    debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
+
+    let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
+    for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+        let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+        let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
+
+        let cause = ObligationCause::new(
+            span,
+            impl_m_hir_id,
+            ObligationCauseCode::CompareImplItemObligation {
+                impl_item_def_id: impl_m.def_id.expect_local(),
+                trait_item_def_id: trait_m.def_id,
+                kind: impl_m.kind,
+            },
+        );
+        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
+    }
+
+    // We now need to check that the signature of the impl method is
+    // compatible with that of the trait method. We do this by
+    // checking that `impl_fty <: trait_fty`.
+    //
+    // FIXME. Unfortunately, this doesn't quite work right now because
+    // associated type normalization is not integrated into subtype
+    // checks. For the comparison to be valid, we need to
+    // normalize the associated types in the impl/trait methods
+    // first. However, because function types bind regions, just
+    // calling `normalize_associated_types_in` would have no effect on
+    // any associated types appearing in the fn arguments or return
+    // type.
+
+    // Compute placeholder form of impl and trait method tys.
+    let tcx = infcx.tcx;
+
+    let mut wf_tys = FxIndexSet::default();
+
+    let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+        impl_m_span,
+        infer::HigherRankedType,
+        tcx.fn_sig(impl_m.def_id),
+    );
+    let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
+
+    let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
+    let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
+    debug!("compare_impl_method: impl_fty={:?}", impl_sig);
+
+    let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+    let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+
+    // Next, add all inputs and output as well-formed tys. Importantly,
+    // we have to do this before normalization, since the normalized ty may
+    // not contain the input parameters. See issue #87748.
+    wf_tys.extend(trait_sig.inputs_and_output.iter());
+    let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
+    // We also have to add the normalized trait signature
+    // as we don't normalize during implied bounds computation.
+    wf_tys.extend(trait_sig.inputs_and_output.iter());
+    let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+
+    debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+
+    // FIXME: We'd want to keep more accurate spans than "the method signature" when
+    // processing the comparison between the trait and impl fn, but we sadly lose them
+    // and point at the whole signature when a trait bound or specific input or output
+    // type would be more appropriate. In other places we have a `Vec<Span>`
+    // corresponding to their `Vec<Predicate>`, but we don't have that here.
+    // Fixing this would improve the output of test `issue-83765.rs`.
+    let result = ocx.sup(&cause, param_env, trait_sig, impl_sig);
+
+    if let Err(terr) = result {
+        debug!(?impl_sig, ?trait_sig, ?terr, "sub_types failed");
+
+        let emitted = report_trait_method_mismatch(
+            &infcx,
+            cause,
+            terr,
+            (trait_m, trait_sig),
+            (impl_m, impl_sig),
+            impl_trait_ref,
+        );
+        return Err(emitted);
+    }
+
+    if check_implied_wf == CheckImpliedWfMode::Check {
+        // We need to check that the impl's args are well-formed given
+        // the hybrid param-env (impl + trait method where-clauses).
+        ocx.register_obligation(traits::Obligation::new(
+            infcx.tcx,
+            ObligationCause::dummy(),
+            param_env,
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
+        ));
+    }
+    let emit_implied_wf_lint = || {
+        infcx.tcx.struct_span_lint_hir(
+            rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+            impl_m_hir_id,
+            infcx.tcx.def_span(impl_m.def_id),
+            "impl method assumes more implied bounds than the corresponding trait method",
+            |lint| lint,
+        );
+    };
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        match check_implied_wf {
+            CheckImpliedWfMode::Check => {
+                return compare_method_predicate_entailment(
+                    tcx,
+                    impl_m,
+                    impl_m_span,
+                    trait_m,
+                    impl_trait_ref,
+                    CheckImpliedWfMode::Skip,
+                )
+                .map(|()| {
+                    // If the skip-mode was successful, emit a lint.
+                    emit_implied_wf_lint();
+                });
+            }
+            CheckImpliedWfMode::Skip => {
+                let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+                return Err(reported);
+            }
+        }
+    }
+
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let outlives_env = OutlivesEnvironment::with_bounds(
+        param_env,
+        Some(infcx),
+        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
+    );
+    infcx.process_registered_region_obligations(
+        outlives_env.region_bound_pairs(),
+        outlives_env.param_env,
+    );
+    let errors = infcx.resolve_regions(&outlives_env);
+    if !errors.is_empty() {
+        // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
+        // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
+        match check_implied_wf {
+            CheckImpliedWfMode::Check => {
+                return compare_method_predicate_entailment(
+                    tcx,
+                    impl_m,
+                    impl_m_span,
+                    trait_m,
+                    impl_trait_ref,
+                    CheckImpliedWfMode::Skip,
+                )
+                .map(|()| {
+                    // If the skip-mode was successful, emit a lint.
+                    emit_implied_wf_lint();
+                });
+            }
+            CheckImpliedWfMode::Skip => {
+                if infcx.tainted_by_errors().is_none() {
+                    infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
+                }
+                return Err(tcx
+                    .sess
+                    .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
+            }
+        }
+    }
+
+    Ok(())
+}
+
+#[derive(Debug, PartialEq, Eq)]
+enum CheckImpliedWfMode {
+    /// Checks implied well-formedness of the impl method. If it fails, we will
+    /// re-check with `Skip`, and emit a lint if it succeeds.
+    Check,
+    /// Skips checking implied well-formedness of the impl method, but will emit
+    /// a lint if the `compare_method_predicate_entailment` succeeded. This means that
+    /// the reason that we had failed earlier during `Check` was due to the impl
+    /// having stronger requirements than the trait.
+    Skip,
+}
+
+fn compare_asyncness<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    impl_m_span: Span,
+    trait_m: &ty::AssocItem,
+    trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+    if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+        match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+            ty::Alias(ty::Opaque, ..) => {
+                // allow both `async fn foo()` and `fn foo() -> impl Future`
+            }
+            ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+                // We don't know if it's ok, but at least it's already an error.
+            }
+            _ => {
+                return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+                    span: impl_m_span,
+                    method_name: trait_m.name,
+                    trait_item_span,
+                }));
+            }
+        };
+    }
+
+    Ok(())
+}
+
+/// Given a method def-id in an impl, compare the method signature of the impl
+/// against the trait that it's implementing. In doing so, infer the hidden types
+/// that this method's signature provides to satisfy each return-position `impl Trait`
+/// in the trait signature.
+///
+/// The method is also responsible for making sure that the hidden types for each
+/// RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer
+/// `impl Trait = Foo`, that `Foo: Trait` holds.
+///
+/// For example, given the sample code:
+///
+/// ```
+/// #![feature(return_position_impl_trait_in_trait)]
+///
+/// use std::ops::Deref;
+///
+/// trait Foo {
+///     fn bar() -> impl Deref<Target = impl Sized>;
+///              // ^- RPITIT #1        ^- RPITIT #2
+/// }
+///
+/// impl Foo for () {
+///     fn bar() -> Box<String> { Box::new(String::new()) }
+/// }
+/// ```
+///
+/// The hidden types for the RPITITs in `bar` would be inferred to:
+///     * `impl Deref` (RPITIT #1) = `Box<String>`
+///     * `impl Sized` (RPITIT #2) = `String`
+///
+/// The relationship between these two types is straightforward in this case, but
+/// may be more tenuously connected via other `impl`s and normalization rules for
+/// cases of more complicated nested RPITITs.
+#[instrument(skip(tcx), level = "debug", ret)]
+pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
+    let impl_m = tcx.opt_associated_item(def_id).unwrap();
+    let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
+    let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+    let param_env = tcx.param_env(def_id);
+
+    // First, check a few of the same things as `compare_impl_method`,
+    // just so we don't ICE during substitution later.
+    compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
+    compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
+    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
+
+    let trait_to_impl_substs = impl_trait_ref.substs;
+
+    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+    let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
+    let cause = ObligationCause::new(
+        return_span,
+        impl_m_hir_id,
+        ObligationCauseCode::CompareImplItemObligation {
+            impl_item_def_id: impl_m.def_id.expect_local(),
+            trait_item_def_id: trait_m.def_id,
+            kind: impl_m.kind,
+        },
+    );
+
+    // Create mapping from impl to placeholder.
+    let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
+
+    // Create mapping from trait to placeholder.
+    let trait_to_placeholder_substs =
+        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
+
+    let infcx = &tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(infcx);
+
+    // Normalize the impl signature with fresh variables for lifetime inference.
+    let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
+    let impl_sig = ocx.normalize(
+        &norm_cause,
+        param_env,
+        infcx.replace_bound_vars_with_fresh_vars(
+            return_span,
+            infer::HigherRankedType,
+            tcx.fn_sig(impl_m.def_id),
+        ),
+    );
+    impl_sig.error_reported()?;
+    let impl_return_ty = impl_sig.output();
+
+    // Normalize the trait signature with liberated bound vars, passing it through
+    // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
+    // them with inference variables.
+    // We will use these inference variables to collect the hidden types of RPITITs.
+    let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+    let unnormalized_trait_sig = tcx
+        .liberate_late_bound_regions(
+            impl_m.def_id,
+            tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+        )
+        .fold_with(&mut collector);
+    let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
+    trait_sig.error_reported()?;
+    let trait_return_ty = trait_sig.output();
+
+    let wf_tys = FxIndexSet::from_iter(
+        unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+    );
+
+    match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
+        Ok(()) => {}
+        Err(terr) => {
+            let mut diag = struct_span_err!(
+                tcx.sess,
+                cause.span(),
+                E0053,
+                "method `{}` has an incompatible return type for trait",
+                trait_m.name
+            );
+            let hir = tcx.hir();
+            infcx.err_ctxt().note_type_err(
+                &mut diag,
+                &cause,
+                hir.get_if_local(impl_m.def_id)
+                    .and_then(|node| node.fn_decl())
+                    .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
+                Some(infer::ValuePairs::Terms(ExpectedFound {
+                    expected: trait_return_ty.into(),
+                    found: impl_return_ty.into(),
+                })),
+                terr,
+                false,
+                false,
+            );
+            return Err(diag.emit());
+        }
+    }
+
+    debug!(?trait_sig, ?impl_sig, "equating function signatures");
+
+    // Unify the whole function signature. We need to do this to fully infer
+    // the lifetimes of the return type, but do this after unifying just the
+    // return types, since we want to avoid duplicating errors from
+    // `compare_method_predicate_entailment`.
+    match ocx.eq(&cause, param_env, trait_sig, impl_sig) {
+        Ok(()) => {}
+        Err(terr) => {
+            // This function gets called during `compare_method_predicate_entailment` when normalizing a
+            // signature that contains RPITIT. When the method signatures don't match, we have to
+            // emit an error now because `compare_method_predicate_entailment` will not report the error
+            // when normalization fails.
+            let emitted = report_trait_method_mismatch(
+                infcx,
+                cause,
+                terr,
+                (trait_m, trait_sig),
+                (impl_m, impl_sig),
+                impl_trait_ref,
+            );
+            return Err(emitted);
+        }
+    }
+
+    // Check that all obligations are satisfied by the implementation's
+    // RPITs.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+        return Err(reported);
+    }
+
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let outlives_environment = OutlivesEnvironment::with_bounds(
+        param_env,
+        Some(infcx),
+        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+    );
+    infcx.err_ctxt().check_region_obligations_and_report_errors(
+        impl_m.def_id.expect_local(),
+        &outlives_environment,
+    )?;
+
+    let mut collected_tys = FxHashMap::default();
+    for (def_id, (ty, substs)) in collector.types {
+        match infcx.fully_resolve(ty) {
+            Ok(ty) => {
+                // `ty` contains free regions that we created earlier while liberating the
+                // trait fn signature.  However, projection normalization expects `ty` to
+                // contains `def_id`'s early-bound regions.
+                let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+                debug!(?id_substs, ?substs);
+                let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
+                    std::iter::zip(substs, id_substs).collect();
+                debug!(?map);
+
+                // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
+                // region substs that are synthesized during AST lowering. These are substs
+                // that are appended to the parent substs (trait and trait method). However,
+                // we're trying to infer the unsubstituted type value of the RPITIT inside
+                // the *impl*, so we can later use the impl's method substs to normalize
+                // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
+                //
+                // Due to the design of RPITITs, during AST lowering, we have no idea that
+                // an impl method corresponds to a trait method with RPITITs in it. Therefore,
+                // we don't have a list of early-bound region substs for the RPITIT in the impl.
+                // Since early region parameters are index-based, we can't just rebase these
+                // (trait method) early-bound region substs onto the impl, and there's no
+                // guarantee that the indices from the trait substs and impl substs line up.
+                // So to fix this, we subtract the number of trait substs and add the number of
+                // impl substs to *renumber* these early-bound regions to their corresponding
+                // indices in the impl's substitutions list.
+                //
+                // Also, we only need to account for a difference in trait and impl substs,
+                // since we previously enforce that the trait method and impl method have the
+                // same generics.
+                let num_trait_substs = trait_to_impl_substs.len();
+                let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
+                let ty = tcx.fold_regions(ty, |region, _| {
+                    match region.kind() {
+                        // Remap all free regions, which correspond to late-bound regions in the function.
+                        ty::ReFree(_) => {}
+                        // Remap early-bound regions as long as they don't come from the `impl` itself.
+                        ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
+                        _ => return region,
+                    }
+                    let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
+                    else {
+                        tcx
+                            .sess
+                            .delay_span_bug(
+                                return_span,
+                                "expected ReFree to map to ReEarlyBound"
+                            );
+                        return tcx.lifetimes.re_static;
+                    };
+                    tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+                        def_id: e.def_id,
+                        name: e.name,
+                        index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
+                    }))
+                });
+                debug!(%ty);
+                collected_tys.insert(def_id, ty);
+            }
+            Err(err) => {
+                let reported = tcx.sess.delay_span_bug(
+                    return_span,
+                    format!("could not fully resolve: {ty} => {err:?}"),
+                );
+                collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
+            }
+        }
+    }
+
+    Ok(&*tcx.arena.alloc(collected_tys))
+}
+
+struct ImplTraitInTraitCollector<'a, 'tcx> {
+    ocx: &'a ObligationCtxt<'a, 'tcx>,
+    types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>,
+    span: Span,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+}
+
+impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
+    fn new(
+        ocx: &'a ObligationCtxt<'a, 'tcx>,
+        span: Span,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+    ) -> Self {
+        ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+        self.ocx.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(ty::Projection, proj) = ty.kind()
+            && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+        {
+            if let Some((ty, _)) = self.types.get(&proj.def_id) {
+                return *ty;
+            }
+            //FIXME(RPITIT): Deny nested RPITIT in substs too
+            if proj.substs.has_escaping_bound_vars() {
+                bug!("FIXME(RPITIT): error here");
+            }
+            // Replace with infer var
+            let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
+                span: self.span,
+                kind: TypeVariableOriginKind::MiscVariable,
+            });
+            self.types.insert(proj.def_id, (infer_ty, proj.substs));
+            // Recurse into bounds
+            for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
+                let pred = pred.fold_with(self);
+                let pred = self.ocx.normalize(
+                    &ObligationCause::misc(self.span, self.body_id),
+                    self.param_env,
+                    pred,
+                );
+
+                self.ocx.register_obligation(traits::Obligation::new(
+                    self.tcx(),
+                    ObligationCause::new(
+                        self.span,
+                        self.body_id,
+                        ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
+                    ),
+                    self.param_env,
+                    pred,
+                ));
+            }
+            infer_ty
+        } else {
+            ty.super_fold_with(self)
+        }
+    }
+}
+
+fn report_trait_method_mismatch<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    mut cause: ObligationCause<'tcx>,
+    terr: TypeError<'tcx>,
+    (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+    (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) -> ErrorGuaranteed {
+    let tcx = infcx.tcx;
+    let (impl_err_span, trait_err_span) =
+        extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+
+    let mut diag = struct_span_err!(
+        tcx.sess,
+        impl_err_span,
+        E0053,
+        "method `{}` has an incompatible type for trait",
+        trait_m.name
+    );
+    match &terr {
+        TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+            if trait_m.fn_has_self_parameter =>
+        {
+            let ty = trait_sig.inputs()[0];
+            let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+                ExplicitSelf::ByValue => "self".to_owned(),
+                ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+                ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+                _ => format!("self: {ty}"),
+            };
+
+            // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+            // span points only at the type `Box<Self`>, but we want to cover the whole
+            // argument pattern and type.
+            let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+                ImplItemKind::Fn(ref sig, body) => tcx
+                    .hir()
+                    .body_param_names(body)
+                    .zip(sig.decl.inputs.iter())
+                    .map(|(param, ty)| param.span.to(ty.span))
+                    .next()
+                    .unwrap_or(impl_err_span),
+                _ => bug!("{:?} is not a method", impl_m),
+            };
+
+            diag.span_suggestion(
+                span,
+                "change the self-receiver type to match the trait",
+                sugg,
+                Applicability::MachineApplicable,
+            );
+        }
+        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+            if trait_sig.inputs().len() == *i {
+                // Suggestion to change output type. We do not suggest in `async` functions
+                // to avoid complex logic or incorrect output.
+                match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+                    ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
+                        let msg = "change the output type to match the trait";
+                        let ap = Applicability::MachineApplicable;
+                        match sig.decl.output {
+                            hir::FnRetTy::DefaultReturn(sp) => {
+                                let sugg = format!("-> {} ", trait_sig.output());
+                                diag.span_suggestion_verbose(sp, msg, sugg, ap);
+                            }
+                            hir::FnRetTy::Return(hir_ty) => {
+                                let sugg = trait_sig.output();
+                                diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                            }
+                        };
+                    }
+                    _ => {}
+                };
+            } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
+                diag.span_suggestion(
+                    impl_err_span,
+                    "change the parameter type to match the trait",
+                    trait_ty,
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+        _ => {}
+    }
+
+    cause.span = impl_err_span;
+    infcx.err_ctxt().note_type_err(
+        &mut diag,
+        &cause,
+        trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+        Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })),
+        terr,
+        false,
+        false,
+    );
+
+    return diag.emit();
+}
+
+fn check_region_bounds_on_impl_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    trait_m: &ty::AssocItem,
+    delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+    let impl_generics = tcx.generics_of(impl_m.def_id);
+    let impl_params = impl_generics.own_counts().lifetimes;
+
+    let trait_generics = tcx.generics_of(trait_m.def_id);
+    let trait_params = trait_generics.own_counts().lifetimes;
+
+    debug!(
+        "check_region_bounds_on_impl_item: \
+            trait_generics={:?} \
+            impl_generics={:?}",
+        trait_generics, impl_generics
+    );
+
+    // Must have same number of early-bound lifetime parameters.
+    // Unfortunately, if the user screws up the bounds, then this
+    // will change classification between early and late.  E.g.,
+    // if in trait we have `<'a,'b:'a>`, and in impl we just have
+    // `<'a,'b>`, then we have 2 early-bound lifetime parameters
+    // in trait but 0 in the impl. But if we report "expected 2
+    // but found 0" it's confusing, because it looks like there
+    // are zero. Since I don't quite know how to phrase things at
+    // the moment, give a kind of vague error message.
+    if trait_params != impl_params {
+        let span = tcx
+            .hir()
+            .get_generics(impl_m.def_id.expect_local())
+            .expect("expected impl item to have generics or else we can't compare them")
+            .span;
+
+        let mut generics_span = None;
+        let mut bounds_span = vec![];
+        let mut where_span = None;
+        if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+            && let Some(trait_generics) = trait_node.generics()
+        {
+            generics_span = Some(trait_generics.span);
+            // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+            // *are* present in the impl.
+            for p in trait_generics.predicates {
+                if let hir::WherePredicate::BoundPredicate(pred) = p {
+                    for b in pred.bounds {
+                        if let hir::GenericBound::Outlives(lt) = b {
+                            bounds_span.push(lt.ident.span);
+                        }
+                    }
+                }
+            }
+            if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+                && let Some(impl_generics) = impl_node.generics()
+            {
+                let mut impl_bounds = 0;
+                for p in impl_generics.predicates {
+                    if let hir::WherePredicate::BoundPredicate(pred) = p {
+                        for b in pred.bounds {
+                            if let hir::GenericBound::Outlives(_) = b {
+                                impl_bounds += 1;
+                            }
+                        }
+                    }
+                }
+                if impl_bounds == bounds_span.len() {
+                    bounds_span = vec![];
+                } else if impl_generics.has_where_clause_predicates {
+                    where_span = Some(impl_generics.where_clause_span);
+                }
+            }
+        }
+        let reported = tcx
+            .sess
+            .create_err(LifetimesOrBoundsMismatchOnTrait {
+                span,
+                item_kind: assoc_item_kind_str(impl_m),
+                ident: impl_m.ident(tcx),
+                generics_span,
+                bounds_span,
+                where_span,
+            })
+            .emit_unless(delay);
+        return Err(reported);
+    }
+
+    Ok(())
+}
+
+#[instrument(level = "debug", skip(infcx))]
+fn extract_spans_for_error_reporting<'tcx>(
+    infcx: &infer::InferCtxt<'tcx>,
+    terr: TypeError<'_>,
+    cause: &ObligationCause<'tcx>,
+    impl_m: &ty::AssocItem,
+    trait_m: &ty::AssocItem,
+) -> (Span, Option<Span>) {
+    let tcx = infcx.tcx;
+    let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+        ImplItemKind::Fn(ref sig, _) => {
+            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
+        }
+        _ => bug!("{:?} is not a method", impl_m),
+    };
+    let trait_args =
+        trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
+            TraitItemKind::Fn(ref sig, _) => {
+                sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
+            }
+            _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
+        });
+
+    match terr {
+        TypeError::ArgumentMutability(i) => {
+            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
+        }
+        TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
+            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
+        }
+        _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
+    }
+}
+
+fn compare_self_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    impl_m_span: Span,
+    trait_m: &ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+    // Try to give more informative error messages about self typing
+    // mismatches.  Note that any mismatch will also be detected
+    // below, where we construct a canonical function type that
+    // includes the self parameter as a normal parameter.  It's just
+    // that the error messages you get out of this code are a bit more
+    // inscrutable, particularly for cases where one method has no
+    // self.
+
+    let self_string = |method: &ty::AssocItem| {
+        let untransformed_self_ty = match method.container {
+            ty::ImplContainer => impl_trait_ref.self_ty(),
+            ty::TraitContainer => tcx.types.self_param,
+        };
+        let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
+        let param_env = ty::ParamEnv::reveal_all();
+
+        let infcx = tcx.infer_ctxt().build();
+        let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
+        let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
+        match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
+            ExplicitSelf::ByValue => "self".to_owned(),
+            ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+            ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+            _ => format!("self: {self_arg_ty}"),
+        }
+    };
+
+    match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
+        (false, false) | (true, true) => {}
+
+        (false, true) => {
+            let self_descr = self_string(impl_m);
+            let mut err = struct_span_err!(
+                tcx.sess,
+                impl_m_span,
+                E0185,
+                "method `{}` has a `{}` declaration in the impl, but not in the trait",
+                trait_m.name,
+                self_descr
+            );
+            err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
+            if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
+                err.span_label(span, format!("trait method declared without `{self_descr}`"));
+            } else {
+                err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+            }
+            let reported = err.emit();
+            return Err(reported);
+        }
+
+        (true, false) => {
+            let self_descr = self_string(trait_m);
+            let mut err = struct_span_err!(
+                tcx.sess,
+                impl_m_span,
+                E0186,
+                "method `{}` has a `{}` declaration in the trait, but not in the impl",
+                trait_m.name,
+                self_descr
+            );
+            err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
+            if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
+                err.span_label(span, format!("`{self_descr}` used in trait"));
+            } else {
+                err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+            }
+            let reported = err.emit();
+            return Err(reported);
+        }
+    }
+
+    Ok(())
+}
+
+/// Checks that the number of generics on a given assoc item in a trait impl is the same
+/// as the number of generics on the respective assoc item in the trait definition.
+///
+/// For example this code emits the errors in the following code:
+/// ```
+/// trait Trait {
+///     fn foo();
+///     type Assoc<T>;
+/// }
+///
+/// impl Trait for () {
+///     fn foo<T>() {}
+///     //~^ error
+///     type Assoc = u32;
+///     //~^ error
+/// }
+/// ```
+///
+/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
+/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
+/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
+fn compare_number_of_generics<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_: &ty::AssocItem,
+    trait_: &ty::AssocItem,
+    trait_span: Option<Span>,
+    delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+    let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
+    let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
+
+    // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
+    // in `compare_generic_param_kinds` which will give a nicer error message than something like:
+    // "expected 1 type parameter, found 0 type parameters"
+    if (trait_own_counts.types + trait_own_counts.consts)
+        == (impl_own_counts.types + impl_own_counts.consts)
+    {
+        return Ok(());
+    }
+
+    let matchings = [
+        ("type", trait_own_counts.types, impl_own_counts.types),
+        ("const", trait_own_counts.consts, impl_own_counts.consts),
+    ];
+
+    let item_kind = assoc_item_kind_str(impl_);
+
+    let mut err_occurred = None;
+    for (kind, trait_count, impl_count) in matchings {
+        if impl_count != trait_count {
+            let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
+                let mut spans = generics
+                    .params
+                    .iter()
+                    .filter(|p| match p.kind {
+                        hir::GenericParamKind::Lifetime {
+                            kind: hir::LifetimeParamKind::Elided,
+                        } => {
+                            // A fn can have an arbitrary number of extra elided lifetimes for the
+                            // same signature.
+                            !matches!(kind, ty::AssocKind::Fn)
+                        }
+                        _ => true,
+                    })
+                    .map(|p| p.span)
+                    .collect::<Vec<Span>>();
+                if spans.is_empty() {
+                    spans = vec![generics.span]
+                }
+                spans
+            };
+            let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
+                let trait_item = tcx.hir().expect_trait_item(def_id);
+                let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
+                let impl_trait_spans: Vec<Span> = trait_item
+                    .generics
+                    .params
+                    .iter()
+                    .filter_map(|p| match p.kind {
+                        GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
+                        _ => None,
+                    })
+                    .collect();
+                (Some(arg_spans), impl_trait_spans)
+            } else {
+                (trait_span.map(|s| vec![s]), vec![])
+            };
+
+            let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
+            let impl_item_impl_trait_spans: Vec<Span> = impl_item
+                .generics
+                .params
+                .iter()
+                .filter_map(|p| match p.kind {
+                    GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
+                    _ => None,
+                })
+                .collect();
+            let spans = arg_spans(impl_.kind, impl_item.generics);
+            let span = spans.first().copied();
+
+            let mut err = tcx.sess.struct_span_err_with_code(
+                spans,
+                &format!(
+                    "{} `{}` has {} {kind} parameter{} but its trait \
+                     declaration has {} {kind} parameter{}",
+                    item_kind,
+                    trait_.name,
+                    impl_count,
+                    pluralize!(impl_count),
+                    trait_count,
+                    pluralize!(trait_count),
+                    kind = kind,
+                ),
+                DiagnosticId::Error("E0049".into()),
+            );
+
+            let mut suffix = None;
+
+            if let Some(spans) = trait_spans {
+                let mut spans = spans.iter();
+                if let Some(span) = spans.next() {
+                    err.span_label(
+                        *span,
+                        format!(
+                            "expected {} {} parameter{}",
+                            trait_count,
+                            kind,
+                            pluralize!(trait_count),
+                        ),
+                    );
+                }
+                for span in spans {
+                    err.span_label(*span, "");
+                }
+            } else {
+                suffix = Some(format!(", expected {trait_count}"));
+            }
+
+            if let Some(span) = span {
+                err.span_label(
+                    span,
+                    format!(
+                        "found {} {} parameter{}{}",
+                        impl_count,
+                        kind,
+                        pluralize!(impl_count),
+                        suffix.unwrap_or_else(String::new),
+                    ),
+                );
+            }
+
+            for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
+                err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
+            }
+
+            let reported = err.emit_unless(delay);
+            err_occurred = Some(reported);
+        }
+    }
+
+    if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) }
+}
+
+fn compare_number_of_method_arguments<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    impl_m_span: Span,
+    trait_m: &ty::AssocItem,
+    trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+    let impl_m_fty = tcx.fn_sig(impl_m.def_id);
+    let trait_m_fty = tcx.fn_sig(trait_m.def_id);
+    let trait_number_args = trait_m_fty.inputs().skip_binder().len();
+    let impl_number_args = impl_m_fty.inputs().skip_binder().len();
+    if trait_number_args != impl_number_args {
+        let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
+            match tcx.hir().expect_trait_item(def_id).kind {
+                TraitItemKind::Fn(ref trait_m_sig, _) => {
+                    let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
+                    if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
+                        Some(if pos == 0 {
+                            arg.span
+                        } else {
+                            arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
+                        })
+                    } else {
+                        trait_item_span
+                    }
+                }
+                _ => bug!("{:?} is not a method", impl_m),
+            }
+        } else {
+            trait_item_span
+        };
+        let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+            ImplItemKind::Fn(ref impl_m_sig, _) => {
+                let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
+                if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
+                    if pos == 0 {
+                        arg.span
+                    } else {
+                        arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
+                    }
+                } else {
+                    impl_m_span
+                }
+            }
+            _ => bug!("{:?} is not a method", impl_m),
+        };
+        let mut err = struct_span_err!(
+            tcx.sess,
+            impl_span,
+            E0050,
+            "method `{}` has {} but the declaration in trait `{}` has {}",
+            trait_m.name,
+            potentially_plural_count(impl_number_args, "parameter"),
+            tcx.def_path_str(trait_m.def_id),
+            trait_number_args
+        );
+        if let Some(trait_span) = trait_span {
+            err.span_label(
+                trait_span,
+                format!(
+                    "trait requires {}",
+                    potentially_plural_count(trait_number_args, "parameter")
+                ),
+            );
+        } else {
+            err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+        }
+        err.span_label(
+            impl_span,
+            format!(
+                "expected {}, found {}",
+                potentially_plural_count(trait_number_args, "parameter"),
+                impl_number_args
+            ),
+        );
+        let reported = err.emit();
+        return Err(reported);
+    }
+
+    Ok(())
+}
+
+fn compare_synthetic_generics<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    trait_m: &ty::AssocItem,
+) -> Result<(), ErrorGuaranteed> {
+    // FIXME(chrisvittal) Clean up this function, list of FIXME items:
+    //     1. Better messages for the span labels
+    //     2. Explanation as to what is going on
+    // If we get here, we already have the same number of generics, so the zip will
+    // be okay.
+    let mut error_found = None;
+    let impl_m_generics = tcx.generics_of(impl_m.def_id);
+    let trait_m_generics = tcx.generics_of(trait_m.def_id);
+    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
+    });
+    let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
+        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
+    });
+    for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
+        iter::zip(impl_m_type_params, trait_m_type_params)
+    {
+        if impl_synthetic != trait_synthetic {
+            let impl_def_id = impl_def_id.expect_local();
+            let impl_span = tcx.def_span(impl_def_id);
+            let trait_span = tcx.def_span(trait_def_id);
+            let mut err = struct_span_err!(
+                tcx.sess,
+                impl_span,
+                E0643,
+                "method `{}` has incompatible signature for trait",
+                trait_m.name
+            );
+            err.span_label(trait_span, "declaration in trait here");
+            match (impl_synthetic, trait_synthetic) {
+                // The case where the impl method uses `impl Trait` but the trait method uses
+                // explicit generics
+                (true, false) => {
+                    err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
+                    (|| {
+                        // try taking the name from the trait impl
+                        // FIXME: this is obviously suboptimal since the name can already be used
+                        // as another generic argument
+                        let new_name = tcx.opt_item_name(trait_def_id)?;
+                        let trait_m = trait_m.def_id.as_local()?;
+                        let trait_m = tcx.hir().expect_trait_item(trait_m);
+
+                        let impl_m = impl_m.def_id.as_local()?;
+                        let impl_m = tcx.hir().expect_impl_item(impl_m);
+
+                        // in case there are no generics, take the spot between the function name
+                        // and the opening paren of the argument list
+                        let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
+                        // in case there are generics, just replace them
+                        let generics_span =
+                            impl_m.generics.span.substitute_dummy(new_generics_span);
+                        // replace with the generics from the trait
+                        let new_generics =
+                            tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;
+
+                        err.multipart_suggestion(
+                            "try changing the `impl Trait` argument to a generic parameter",
+                            vec![
+                                // replace `impl Trait` with `T`
+                                (impl_span, new_name.to_string()),
+                                // replace impl method generics with trait method generics
+                                // This isn't quite right, as users might have changed the names
+                                // of the generics, but it works for the common case
+                                (generics_span, new_generics),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                        Some(())
+                    })();
+                }
+                // The case where the trait method uses `impl Trait`, but the impl method uses
+                // explicit generics.
+                (false, true) => {
+                    err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
+                    (|| {
+                        let impl_m = impl_m.def_id.as_local()?;
+                        let impl_m = tcx.hir().expect_impl_item(impl_m);
+                        let input_tys = match impl_m.kind {
+                            hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
+                            _ => unreachable!(),
+                        };
+                        struct Visitor(Option<Span>, hir::def_id::LocalDefId);
+                        impl<'v> intravisit::Visitor<'v> for Visitor {
+                            fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+                                intravisit::walk_ty(self, ty);
+                                if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
+                                    ty.kind
+                                    && let Res::Def(DefKind::TyParam, def_id) = path.res
+                                    && def_id == self.1.to_def_id()
+                                {
+                                    self.0 = Some(ty.span);
+                                }
+                            }
+                        }
+                        let mut visitor = Visitor(None, impl_def_id);
+                        for ty in input_tys {
+                            intravisit::Visitor::visit_ty(&mut visitor, ty);
+                        }
+                        let span = visitor.0?;
+
+                        let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
+                        let bounds = bounds.first()?.span().to(bounds.last()?.span());
+                        let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
+
+                        err.multipart_suggestion(
+                            "try removing the generic parameter and using `impl Trait` instead",
+                            vec![
+                                // delete generic parameters
+                                (impl_m.generics.span, String::new()),
+                                // replace param usage with `impl Trait`
+                                (span, format!("impl {bounds}")),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                        Some(())
+                    })();
+                }
+                _ => unreachable!(),
+            }
+            let reported = err.emit();
+            error_found = Some(reported);
+        }
+    }
+    if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
+}
+
+/// Checks that all parameters in the generics of a given assoc item in a trait impl have
+/// the same kind as the respective generic parameter in the trait def.
+///
+/// For example all 4 errors in the following code are emitted here:
+/// ```
+/// trait Foo {
+///     fn foo<const N: u8>();
+///     type bar<const N: u8>;
+///     fn baz<const N: u32>();
+///     type blah<T>;
+/// }
+///
+/// impl Foo for () {
+///     fn foo<const N: u64>() {}
+///     //~^ error
+///     type bar<const N: u64> {}
+///     //~^ error
+///     fn baz<T>() {}
+///     //~^ error
+///     type blah<const N: i64> = u32;
+///     //~^ error
+/// }
+/// ```
+///
+/// This function does not handle lifetime parameters
+fn compare_generic_param_kinds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_item: &ty::AssocItem,
+    trait_item: &ty::AssocItem,
+    delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+    assert_eq!(impl_item.kind, trait_item.kind);
+
+    let ty_const_params_of = |def_id| {
+        tcx.generics_of(def_id).params.iter().filter(|param| {
+            matches!(
+                param.kind,
+                GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
+            )
+        })
+    };
+
+    for (param_impl, param_trait) in
+        iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
+    {
+        use GenericParamDefKind::*;
+        if match (&param_impl.kind, &param_trait.kind) {
+            (Const { .. }, Const { .. })
+                if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
+            {
+                true
+            }
+            (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
+            // this is exhaustive so that anyone adding new generic param kinds knows
+            // to make sure this error is reported for them.
+            (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
+            (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
+        } {
+            let param_impl_span = tcx.def_span(param_impl.def_id);
+            let param_trait_span = tcx.def_span(param_trait.def_id);
+
+            let mut err = struct_span_err!(
+                tcx.sess,
+                param_impl_span,
+                E0053,
+                "{} `{}` has an incompatible generic parameter for trait `{}`",
+                assoc_item_kind_str(&impl_item),
+                trait_item.name,
+                &tcx.def_path_str(tcx.parent(trait_item.def_id))
+            );
+
+            let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
+                Const { .. } => {
+                    format!("{} const parameter of type `{}`", prefix, tcx.type_of(param.def_id))
+                }
+                Type { .. } => format!("{} type parameter", prefix),
+                Lifetime { .. } => unreachable!(),
+            };
+
+            let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
+            err.span_label(trait_header_span, "");
+            err.span_label(param_trait_span, make_param_message("expected", param_trait));
+
+            let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id));
+            err.span_label(impl_header_span, "");
+            err.span_label(param_impl_span, make_param_message("found", param_impl));
+
+            let reported = err.emit_unless(delay);
+            return Err(reported);
+        }
+    }
+
+    Ok(())
+}
+
+/// Use `tcx.compare_impl_const` instead
+pub(super) fn compare_impl_const_raw(
+    tcx: TyCtxt<'_>,
+    (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
+) -> Result<(), ErrorGuaranteed> {
+    let impl_const_item = tcx.associated_item(impl_const_item_def);
+    let trait_const_item = tcx.associated_item(trait_const_item_def);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
+    debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
+
+    let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
+
+    let infcx = tcx.infer_ctxt().build();
+    let param_env = tcx.param_env(impl_const_item_def.to_def_id());
+    let ocx = ObligationCtxt::new(&infcx);
+
+    // The below is for the most part highly similar to the procedure
+    // for methods above. It is simpler in many respects, especially
+    // because we shouldn't really have to deal with lifetimes or
+    // predicates. In fact some of this should probably be put into
+    // shared functions because of DRY violations...
+    let trait_to_impl_substs = impl_trait_ref.substs;
+
+    // Create a parameter environment that represents the implementation's
+    // method.
+    let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
+
+    // Compute placeholder form of impl and trait const tys.
+    let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
+    let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
+    let mut cause = ObligationCause::new(
+        impl_c_span,
+        impl_c_hir_id,
+        ObligationCauseCode::CompareImplItemObligation {
+            impl_item_def_id: impl_const_item_def,
+            trait_item_def_id: trait_const_item_def,
+            kind: impl_const_item.kind,
+        },
+    );
+
+    // There is no "body" here, so just pass dummy id.
+    let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
+
+    debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+
+    let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
+
+    debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+
+    let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
+
+    if let Err(terr) = err {
+        debug!(
+            "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+            impl_ty, trait_ty
+        );
+
+        // Locate the Span containing just the type of the offending impl
+        match tcx.hir().expect_impl_item(impl_const_item_def).kind {
+            ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
+            _ => bug!("{:?} is not a impl const", impl_const_item),
+        }
+
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            cause.span,
+            E0326,
+            "implemented const `{}` has an incompatible type for trait",
+            trait_const_item.name
+        );
+
+        let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
+            // Add a label to the Span containing just the type of the const
+            match tcx.hir().expect_trait_item(trait_c_def_id).kind {
+                TraitItemKind::Const(ref ty, _) => ty.span,
+                _ => bug!("{:?} is not a trait const", trait_const_item),
+            }
+        });
+
+        infcx.err_ctxt().note_type_err(
+            &mut diag,
+            &cause,
+            trait_c_span.map(|span| (span, "type in trait".to_owned())),
+            Some(infer::ValuePairs::Terms(ExpectedFound {
+                expected: trait_ty.into(),
+                found: impl_ty.into(),
+            })),
+            terr,
+            false,
+            false,
+        );
+        return Err(diag.emit());
+    };
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
+    }
+
+    let outlives_environment = OutlivesEnvironment::new(param_env);
+    infcx
+        .err_ctxt()
+        .check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?;
+    Ok(())
+}
+
+pub(super) fn compare_impl_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_ty: &ty::AssocItem,
+    impl_ty_span: Span,
+    trait_ty: &ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    trait_item_span: Option<Span>,
+) {
+    debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
+
+    let _: Result<(), ErrorGuaranteed> = (|| {
+        compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
+
+        compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
+
+        let sp = tcx.def_span(impl_ty.def_id);
+        compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
+
+        check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
+    })();
+}
+
+/// The equivalent of [compare_method_predicate_entailment], but for associated types
+/// instead of associated functions.
+fn compare_type_predicate_entailment<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_ty: &ty::AssocItem,
+    impl_ty_span: Span,
+    trait_ty: &ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+    let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+    let trait_to_impl_substs =
+        impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
+
+    let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
+    let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
+
+    check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
+
+    let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
+
+    if impl_ty_own_bounds.is_empty() {
+        // Nothing to check.
+        return Ok(());
+    }
+
+    // This `HirId` should be used for the `body_id` field on each
+    // `ObligationCause` (and the `FnCtxt`). This is what
+    // `regionck_item` expects.
+    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
+    debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
+
+    // The predicates declared by the impl definition, the trait and the
+    // associated type in the trait are assumed.
+    let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
+    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
+    hybrid_preds
+        .predicates
+        .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
+
+    debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
+
+    let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+    let param_env = ty::ParamEnv::new(
+        tcx.intern_predicates(&hybrid_preds.predicates),
+        Reveal::UserFacing,
+        hir::Constness::NotConst,
+    );
+    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
+
+    debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
+
+    assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+    for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+    {
+        let cause = ObligationCause::misc(span, impl_ty_hir_id);
+        let predicate = ocx.normalize(&cause, param_env, predicate);
+
+        let cause = ObligationCause::new(
+            span,
+            impl_ty_hir_id,
+            ObligationCauseCode::CompareImplItemObligation {
+                impl_item_def_id: impl_ty.def_id.expect_local(),
+                trait_item_def_id: trait_ty.def_id,
+                kind: impl_ty.kind,
+            },
+        );
+        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
+    }
+
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+        return Err(reported);
+    }
+
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let outlives_environment = OutlivesEnvironment::new(param_env);
+    infcx.err_ctxt().check_region_obligations_and_report_errors(
+        impl_ty.def_id.expect_local(),
+        &outlives_environment,
+    )?;
+
+    Ok(())
+}
+
+/// Validate that `ProjectionCandidate`s created for this associated type will
+/// be valid.
+///
+/// Usually given
+///
+/// trait X { type Y: Copy } impl X for T { type Y = S; }
+///
+/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
+/// impl is well-formed we have to prove `S: Copy`.
+///
+/// For default associated types the normalization is not possible (the value
+/// from the impl could be overridden). We also can't normalize generic
+/// associated types (yet) because they contain bound parameters.
+#[instrument(level = "debug", skip(tcx))]
+pub(super) fn check_type_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ty: &ty::AssocItem,
+    impl_ty: &ty::AssocItem,
+    impl_ty_span: Span,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorGuaranteed> {
+    // Given
+    //
+    // impl<A, B> Foo<u32> for (A, B) {
+    //     type Bar<C> =...
+    // }
+    //
+    // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
+    // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
+    // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
+    //    the *trait* with the generic associated type parameters (as bound vars).
+    //
+    // A note regarding the use of bound vars here:
+    // Imagine as an example
+    // ```
+    // trait Family {
+    //     type Member<C: Eq>;
+    // }
+    //
+    // impl Family for VecFamily {
+    //     type Member<C: Eq> = i32;
+    // }
+    // ```
+    // Here, we would generate
+    // ```notrust
+    // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
+    // ```
+    // when we really would like to generate
+    // ```notrust
+    // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
+    // ```
+    // But, this is probably fine, because although the first clause can be used with types C that
+    // do not implement Eq, for it to cause some kind of problem, there would have to be a
+    // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
+    // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
+    // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
+    // the trait (notably, that X: Eq and T: Family).
+    let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
+    let mut substs = smallvec::SmallVec::with_capacity(defs.count());
+    if let Some(def_id) = defs.parent {
+        let parent_defs = tcx.generics_of(def_id);
+        InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
+            tcx.mk_param_from_def(param)
+        });
+    }
+    let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
+        smallvec::SmallVec::with_capacity(defs.count());
+    InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
+        GenericParamDefKind::Type { .. } => {
+            let kind = ty::BoundTyKind::Param(param.name);
+            let bound_var = ty::BoundVariableKind::Ty(kind);
+            bound_vars.push(bound_var);
+            tcx.mk_ty(ty::Bound(
+                ty::INNERMOST,
+                ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+            ))
+            .into()
+        }
+        GenericParamDefKind::Lifetime => {
+            let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
+            let bound_var = ty::BoundVariableKind::Region(kind);
+            bound_vars.push(bound_var);
+            tcx.mk_region(ty::ReLateBound(
+                ty::INNERMOST,
+                ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+            ))
+            .into()
+        }
+        GenericParamDefKind::Const { .. } => {
+            let bound_var = ty::BoundVariableKind::Const;
+            bound_vars.push(bound_var);
+            tcx.mk_const(
+                ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
+                tcx.type_of(param.def_id),
+            )
+            .into()
+        }
+    });
+    let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
+    let impl_ty_substs = tcx.intern_substs(&substs);
+    let container_id = impl_ty.container_id(tcx);
+
+    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
+    let impl_ty_value = tcx.type_of(impl_ty.def_id);
+
+    let param_env = tcx.param_env(impl_ty.def_id);
+
+    // When checking something like
+    //
+    // trait X { type Y: PartialEq<<Self as X>::Y> }
+    // impl X for T { default type Y = S; }
+    //
+    // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
+    // we want <T as X>::Y to normalize to S. This is valid because we are
+    // checking the default value specifically here. Add this equality to the
+    // ParamEnv for normalization specifically.
+    let normalize_param_env = {
+        let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
+        match impl_ty_value.kind() {
+            ty::Alias(ty::Projection, proj)
+                if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
+            {
+                // Don't include this predicate if the projected type is
+                // exactly the same as the projection. This can occur in
+                // (somewhat dubious) code like this:
+                //
+                // impl<T> X for T where T: X { type Y = <T as X>::Y; }
+            }
+            _ => predicates.push(
+                ty::Binder::bind_with_vars(
+                    ty::ProjectionPredicate {
+                        projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
+                        term: impl_ty_value.into(),
+                    },
+                    bound_vars,
+                )
+                .to_predicate(tcx),
+            ),
+        };
+        ty::ParamEnv::new(
+            tcx.intern_predicates(&predicates),
+            Reveal::UserFacing,
+            param_env.constness(),
+        )
+    };
+    debug!(?normalize_param_env);
+
+    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
+    let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
+
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
+
+    let assumed_wf_types =
+        ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
+
+    let normalize_cause = ObligationCause::new(
+        impl_ty_span,
+        impl_ty_hir_id,
+        ObligationCauseCode::CheckAssociatedTypeBounds {
+            impl_item_def_id: impl_ty.def_id.expect_local(),
+            trait_item_def_id: trait_ty.def_id,
+        },
+    );
+    let mk_cause = |span: Span| {
+        let code = if span.is_dummy() {
+            traits::ItemObligation(trait_ty.def_id)
+        } else {
+            traits::BindingObligation(trait_ty.def_id, span)
+        };
+        ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+    };
+
+    let obligations = tcx
+        .bound_explicit_item_bounds(trait_ty.def_id)
+        .subst_iter_copied(tcx, rebased_substs)
+        .map(|(concrete_ty_bound, span)| {
+            debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
+            traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
+        })
+        .collect();
+    debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+    for mut obligation in util::elaborate_obligations(tcx, obligations) {
+        let normalized_predicate =
+            ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
+        debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+        obligation.predicate = normalized_predicate;
+
+        ocx.register_obligation(obligation);
+    }
+    // Check that all obligations are satisfied by the implementation's
+    // version.
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+        return Err(reported);
+    }
+
+    // Finally, resolve all regions. This catches wily misuses of
+    // lifetime parameters.
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
+    let outlives_environment =
+        OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
+
+    infcx.err_ctxt().check_region_obligations_and_report_errors(
+        impl_ty.def_id.expect_local(),
+        &outlives_environment,
+    )?;
+
+    let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    for (key, value) in constraints {
+        infcx
+            .err_ctxt()
+            .report_mismatched_types(
+                &ObligationCause::misc(
+                    value.hidden_type.span,
+                    tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
+                ),
+                tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
+                value.hidden_type.ty,
+                TypeError::Mismatch,
+            )
+            .emit();
+    }
+
+    Ok(())
+}
+
+fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
+    match impl_item.kind {
+        ty::AssocKind::Const => "const",
+        ty::AssocKind::Fn => "method",
+        ty::AssocKind::Type => "type",
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
deleted file mode 100644 (file)
index c6bda9b..0000000
+++ /dev/null
@@ -1,1974 +0,0 @@
-use super::potentially_plural_count;
-use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use hir::def_id::{DefId, LocalDefId};
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit;
-use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::util;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{
-    self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
-};
-use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
-use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
-};
-use std::iter;
-
-/// Checks that a method from an impl conforms to the signature of
-/// the same method as declared in the trait.
-///
-/// # Parameters
-///
-/// - `impl_m`: type of the method we are checking
-/// - `impl_m_span`: span to use for reporting errors
-/// - `trait_m`: the method in the trait
-/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
-pub(crate) fn compare_impl_method<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    trait_m: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    trait_item_span: Option<Span>,
-) {
-    debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
-
-    let impl_m_span = tcx.def_span(impl_m.def_id);
-
-    if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
-        return;
-    }
-
-    if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
-        return;
-    }
-
-    if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
-        return;
-    }
-
-    if let Err(_) =
-        compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
-    {
-        return;
-    }
-
-    if let Err(_) = compare_synthetic_generics(tcx, impl_m, trait_m) {
-        return;
-    }
-
-    if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
-        return;
-    }
-
-    if let Err(_) = compare_predicate_entailment(
-        tcx,
-        impl_m,
-        impl_m_span,
-        trait_m,
-        impl_trait_ref,
-        CheckImpliedWfMode::Check,
-    ) {
-        return;
-    }
-}
-
-/// This function is best explained by example. Consider a trait:
-///
-///     trait Trait<'t, T> {
-///         // `trait_m`
-///         fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
-///     }
-///
-/// And an impl:
-///
-///     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
-///          // `impl_m`
-///          fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
-///     }
-///
-/// We wish to decide if those two method types are compatible.
-/// For this we have to show that, assuming the bounds of the impl hold, the
-/// bounds of `trait_m` imply the bounds of `impl_m`.
-///
-/// We start out with `trait_to_impl_substs`, that maps the trait
-/// type parameters to impl type parameters. This is taken from the
-/// impl trait reference:
-///
-///     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
-///
-/// We create a mapping `dummy_substs` that maps from the impl type
-/// parameters to fresh types and regions. For type parameters,
-/// this is the identity transform, but we could as well use any
-/// placeholder types. For regions, we convert from bound to free
-/// regions (Note: but only early-bound regions, i.e., those
-/// declared on the impl or used in type parameter bounds).
-///
-///     impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
-///
-/// Now we can apply `placeholder_substs` to the type of the impl method
-/// to yield a new function type in terms of our fresh, placeholder
-/// types:
-///
-///     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
-///
-/// We now want to extract and substitute the type of the *trait*
-/// method and compare it. To do so, we must create a compound
-/// substitution by combining `trait_to_impl_substs` and
-/// `impl_to_placeholder_substs`, and also adding a mapping for the method
-/// type parameters. We extend the mapping to also include
-/// the method parameters.
-///
-///     trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
-///
-/// Applying this to the trait method type yields:
-///
-///     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
-///
-/// This type is also the same but the name of the bound region (`'a`
-/// vs `'b`).  However, the normal subtyping rules on fn types handle
-/// this kind of equivalency just fine.
-///
-/// We now use these substitutions to ensure that all declared bounds are
-/// satisfied by the implementation's method.
-///
-/// We do this by creating a parameter environment which contains a
-/// substitution corresponding to `impl_to_placeholder_substs`. We then build
-/// `trait_to_placeholder_substs` and use it to convert the predicates contained
-/// in the `trait_m` generics to the placeholder form.
-///
-/// Finally we register each of these predicates as an obligation and check that
-/// they hold.
-#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
-fn compare_predicate_entailment<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    impl_m_span: Span,
-    trait_m: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    check_implied_wf: CheckImpliedWfMode,
-) -> Result<(), ErrorGuaranteed> {
-    let trait_to_impl_substs = impl_trait_ref.substs;
-
-    // This node-id should be used for the `body_id` field on each
-    // `ObligationCause` (and the `FnCtxt`).
-    //
-    // FIXME(@lcnr): remove that after removing `cause.body_id` from
-    // obligations.
-    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
-    let cause = ObligationCause::new(
-        impl_m_span,
-        impl_m_hir_id,
-        ObligationCauseCode::CompareImplItemObligation {
-            impl_item_def_id: impl_m.def_id.expect_local(),
-            trait_item_def_id: trait_m.def_id,
-            kind: impl_m.kind,
-        },
-    );
-
-    // Create mapping from impl to placeholder.
-    let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
-
-    // Create mapping from trait to placeholder.
-    let trait_to_placeholder_substs =
-        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
-    debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
-
-    let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
-    let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
-
-    // Check region bounds.
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
-
-    // Create obligations for each predicate declared by the impl
-    // definition in the context of the trait's parameter
-    // environment. We can't just use `impl_env.caller_bounds`,
-    // however, because we want to replace all late-bound regions with
-    // region variables.
-    let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
-    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-
-    debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
-
-    // This is the only tricky bit of the new way we check implementation methods
-    // We need to build a set of predicates where only the method-level bounds
-    // are from the trait and we assume all other bounds from the implementation
-    // to be previously satisfied.
-    //
-    // We then register the obligations from the impl_m and check to see
-    // if all constraints hold.
-    hybrid_preds
-        .predicates
-        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
-
-    // Construct trait parameter environment and then shift it into the placeholder viewpoint.
-    // The key step here is to update the caller_bounds's predicates to be
-    // the new hybrid bounds we computed.
-    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
-    let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
-        Reveal::UserFacing,
-        hir::Constness::NotConst,
-    );
-    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
-
-    let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
-
-    debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
-
-    let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
-    for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
-        let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
-        let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
-
-        let cause = ObligationCause::new(
-            span,
-            impl_m_hir_id,
-            ObligationCauseCode::CompareImplItemObligation {
-                impl_item_def_id: impl_m.def_id.expect_local(),
-                trait_item_def_id: trait_m.def_id,
-                kind: impl_m.kind,
-            },
-        );
-        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
-    }
-
-    // We now need to check that the signature of the impl method is
-    // compatible with that of the trait method. We do this by
-    // checking that `impl_fty <: trait_fty`.
-    //
-    // FIXME. Unfortunately, this doesn't quite work right now because
-    // associated type normalization is not integrated into subtype
-    // checks. For the comparison to be valid, we need to
-    // normalize the associated types in the impl/trait methods
-    // first. However, because function types bind regions, just
-    // calling `normalize_associated_types_in` would have no effect on
-    // any associated types appearing in the fn arguments or return
-    // type.
-
-    // Compute placeholder form of impl and trait method tys.
-    let tcx = infcx.tcx;
-
-    let mut wf_tys = FxIndexSet::default();
-
-    let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
-        impl_m_span,
-        infer::HigherRankedType,
-        tcx.fn_sig(impl_m.def_id),
-    );
-    let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
-
-    let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
-    let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty);
-    debug!("compare_impl_method: impl_fty={:?}", impl_fty);
-
-    let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
-    let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
-
-    // Next, add all inputs and output as well-formed tys. Importantly,
-    // we have to do this before normalization, since the normalized ty may
-    // not contain the input parameters. See issue #87748.
-    wf_tys.extend(trait_sig.inputs_and_output.iter());
-    let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
-    // We also have to add the normalized trait signature
-    // as we don't normalize during implied bounds computation.
-    wf_tys.extend(trait_sig.inputs_and_output.iter());
-    let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
-
-    debug!("compare_impl_method: trait_fty={:?}", trait_fty);
-
-    // FIXME: We'd want to keep more accurate spans than "the method signature" when
-    // processing the comparison between the trait and impl fn, but we sadly lose them
-    // and point at the whole signature when a trait bound or specific input or output
-    // type would be more appropriate. In other places we have a `Vec<Span>`
-    // corresponding to their `Vec<Predicate>`, but we don't have that here.
-    // Fixing this would improve the output of test `issue-83765.rs`.
-    let result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
-
-    if let Err(terr) = result {
-        debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
-
-        let emitted = report_trait_method_mismatch(
-            &infcx,
-            cause,
-            terr,
-            (trait_m, trait_fty),
-            (impl_m, impl_fty),
-            trait_sig,
-            impl_trait_ref,
-        );
-        return Err(emitted);
-    }
-
-    if check_implied_wf == CheckImpliedWfMode::Check {
-        // We need to check that the impl's args are well-formed given
-        // the hybrid param-env (impl + trait method where-clauses).
-        ocx.register_obligation(traits::Obligation::new(
-            infcx.tcx,
-            ObligationCause::dummy(),
-            param_env,
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
-        ));
-    }
-    let emit_implied_wf_lint = || {
-        infcx.tcx.struct_span_lint_hir(
-            rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
-            impl_m_hir_id,
-            infcx.tcx.def_span(impl_m.def_id),
-            "impl method assumes more implied bounds than the corresponding trait method",
-            |lint| lint,
-        );
-    };
-
-    // Check that all obligations are satisfied by the implementation's
-    // version.
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        match check_implied_wf {
-            CheckImpliedWfMode::Check => {
-                return compare_predicate_entailment(
-                    tcx,
-                    impl_m,
-                    impl_m_span,
-                    trait_m,
-                    impl_trait_ref,
-                    CheckImpliedWfMode::Skip,
-                )
-                .map(|()| {
-                    // If the skip-mode was successful, emit a lint.
-                    emit_implied_wf_lint();
-                });
-            }
-            CheckImpliedWfMode::Skip => {
-                let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-                return Err(reported);
-            }
-        }
-    }
-
-    // Finally, resolve all regions. This catches wily misuses of
-    // lifetime parameters.
-    let outlives_env = OutlivesEnvironment::with_bounds(
-        param_env,
-        Some(infcx),
-        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
-    );
-    infcx.process_registered_region_obligations(
-        outlives_env.region_bound_pairs(),
-        outlives_env.param_env,
-    );
-    let errors = infcx.resolve_regions(&outlives_env);
-    if !errors.is_empty() {
-        // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
-        // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
-        match check_implied_wf {
-            CheckImpliedWfMode::Check => {
-                return compare_predicate_entailment(
-                    tcx,
-                    impl_m,
-                    impl_m_span,
-                    trait_m,
-                    impl_trait_ref,
-                    CheckImpliedWfMode::Skip,
-                )
-                .map(|()| {
-                    // If the skip-mode was successful, emit a lint.
-                    emit_implied_wf_lint();
-                });
-            }
-            CheckImpliedWfMode::Skip => {
-                if infcx.tainted_by_errors().is_none() {
-                    infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
-                }
-                return Err(tcx
-                    .sess
-                    .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
-            }
-        }
-    }
-
-    Ok(())
-}
-
-#[derive(Debug, PartialEq, Eq)]
-enum CheckImpliedWfMode {
-    /// Checks implied well-formedness of the impl method. If it fails, we will
-    /// re-check with `Skip`, and emit a lint if it succeeds.
-    Check,
-    /// Skips checking implied well-formedness of the impl method, but will emit
-    /// a lint if the `compare_predicate_entailment` succeeded. This means that
-    /// the reason that we had failed earlier during `Check` was due to the impl
-    /// having stronger requirements than the trait.
-    Skip,
-}
-
-fn compare_asyncness<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    impl_m_span: Span,
-    trait_m: &ty::AssocItem,
-    trait_item_span: Option<Span>,
-) -> Result<(), ErrorGuaranteed> {
-    if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
-        match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
-            ty::Alias(ty::Opaque, ..) => {
-                // allow both `async fn foo()` and `fn foo() -> impl Future`
-            }
-            ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
-                // We don't know if it's ok, but at least it's already an error.
-            }
-            _ => {
-                return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
-                    span: impl_m_span,
-                    method_name: trait_m.name,
-                    trait_item_span,
-                }));
-            }
-        };
-    }
-
-    Ok(())
-}
-
-#[instrument(skip(tcx), level = "debug", ret)]
-pub fn collect_trait_impl_trait_tys<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
-    let impl_m = tcx.opt_associated_item(def_id).unwrap();
-    let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
-    let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
-    let param_env = tcx.param_env(def_id);
-
-    // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later.
-    compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
-    compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
-
-    let trait_to_impl_substs = impl_trait_ref.substs;
-
-    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
-    let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
-    let cause = ObligationCause::new(
-        return_span,
-        impl_m_hir_id,
-        ObligationCauseCode::CompareImplItemObligation {
-            impl_item_def_id: impl_m.def_id.expect_local(),
-            trait_item_def_id: trait_m.def_id,
-            kind: impl_m.kind,
-        },
-    );
-
-    // Create mapping from impl to placeholder.
-    let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
-
-    // Create mapping from trait to placeholder.
-    let trait_to_placeholder_substs =
-        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
-
-    let infcx = &tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(infcx);
-
-    // Normalize the impl signature with fresh variables for lifetime inference.
-    let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
-    let impl_sig = ocx.normalize(
-        &norm_cause,
-        param_env,
-        infcx.replace_bound_vars_with_fresh_vars(
-            return_span,
-            infer::HigherRankedType,
-            tcx.fn_sig(impl_m.def_id),
-        ),
-    );
-    impl_sig.error_reported()?;
-    let impl_return_ty = impl_sig.output();
-
-    // Normalize the trait signature with liberated bound vars, passing it through
-    // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
-    // them with inference variables.
-    // We will use these inference variables to collect the hidden types of RPITITs.
-    let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
-    let unnormalized_trait_sig = tcx
-        .liberate_late_bound_regions(
-            impl_m.def_id,
-            tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
-        )
-        .fold_with(&mut collector);
-    let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
-    trait_sig.error_reported()?;
-    let trait_return_ty = trait_sig.output();
-
-    let wf_tys = FxIndexSet::from_iter(
-        unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
-    );
-
-    match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
-        Ok(()) => {}
-        Err(terr) => {
-            let mut diag = struct_span_err!(
-                tcx.sess,
-                cause.span(),
-                E0053,
-                "method `{}` has an incompatible return type for trait",
-                trait_m.name
-            );
-            let hir = tcx.hir();
-            infcx.err_ctxt().note_type_err(
-                &mut diag,
-                &cause,
-                hir.get_if_local(impl_m.def_id)
-                    .and_then(|node| node.fn_decl())
-                    .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
-                Some(infer::ValuePairs::Terms(ExpectedFound {
-                    expected: trait_return_ty.into(),
-                    found: impl_return_ty.into(),
-                })),
-                terr,
-                false,
-                false,
-            );
-            return Err(diag.emit());
-        }
-    }
-
-    debug!(?trait_sig, ?impl_sig, "equating function signatures");
-
-    let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
-    let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
-
-    // Unify the whole function signature. We need to do this to fully infer
-    // the lifetimes of the return type, but do this after unifying just the
-    // return types, since we want to avoid duplicating errors from
-    // `compare_predicate_entailment`.
-    match ocx.eq(&cause, param_env, trait_fty, impl_fty) {
-        Ok(()) => {}
-        Err(terr) => {
-            // This function gets called during `compare_predicate_entailment` when normalizing a
-            // signature that contains RPITIT. When the method signatures don't match, we have to
-            // emit an error now because `compare_predicate_entailment` will not report the error
-            // when normalization fails.
-            let emitted = report_trait_method_mismatch(
-                infcx,
-                cause,
-                terr,
-                (trait_m, trait_fty),
-                (impl_m, impl_fty),
-                trait_sig,
-                impl_trait_ref,
-            );
-            return Err(emitted);
-        }
-    }
-
-    // Check that all obligations are satisfied by the implementation's
-    // RPITs.
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-        return Err(reported);
-    }
-
-    // Finally, resolve all regions. This catches wily misuses of
-    // lifetime parameters.
-    let outlives_environment = OutlivesEnvironment::with_bounds(
-        param_env,
-        Some(infcx),
-        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
-    );
-    infcx.check_region_obligations_and_report_errors(
-        impl_m.def_id.expect_local(),
-        &outlives_environment,
-    );
-
-    let mut collected_tys = FxHashMap::default();
-    for (def_id, (ty, substs)) in collector.types {
-        match infcx.fully_resolve(ty) {
-            Ok(ty) => {
-                // `ty` contains free regions that we created earlier while liberating the
-                // trait fn signature.  However, projection normalization expects `ty` to
-                // contains `def_id`'s early-bound regions.
-                let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
-                debug!(?id_substs, ?substs);
-                let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
-                    std::iter::zip(substs, id_substs).collect();
-                debug!(?map);
-
-                // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
-                // region substs that are synthesized during AST lowering. These are substs
-                // that are appended to the parent substs (trait and trait method). However,
-                // we're trying to infer the unsubstituted type value of the RPITIT inside
-                // the *impl*, so we can later use the impl's method substs to normalize
-                // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
-                //
-                // Due to the design of RPITITs, during AST lowering, we have no idea that
-                // an impl method corresponds to a trait method with RPITITs in it. Therefore,
-                // we don't have a list of early-bound region substs for the RPITIT in the impl.
-                // Since early region parameters are index-based, we can't just rebase these
-                // (trait method) early-bound region substs onto the impl, and there's no
-                // guarantee that the indices from the trait substs and impl substs line up.
-                // So to fix this, we subtract the number of trait substs and add the number of
-                // impl substs to *renumber* these early-bound regions to their corresponding
-                // indices in the impl's substitutions list.
-                //
-                // Also, we only need to account for a difference in trait and impl substs,
-                // since we previously enforce that the trait method and impl method have the
-                // same generics.
-                let num_trait_substs = trait_to_impl_substs.len();
-                let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
-                let ty = tcx.fold_regions(ty, |region, _| {
-                    match region.kind() {
-                        // Remap all free regions, which correspond to late-bound regions in the function.
-                        ty::ReFree(_) => {}
-                        // Remap early-bound regions as long as they don't come from the `impl` itself.
-                        ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
-                        _ => return region,
-                    }
-                    let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
-                    else {
-                        tcx
-                            .sess
-                            .delay_span_bug(
-                                return_span,
-                                "expected ReFree to map to ReEarlyBound"
-                            );
-                        return tcx.lifetimes.re_static;
-                    };
-                    tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
-                        def_id: e.def_id,
-                        name: e.name,
-                        index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
-                    }))
-                });
-                debug!(%ty);
-                collected_tys.insert(def_id, ty);
-            }
-            Err(err) => {
-                let reported = tcx.sess.delay_span_bug(
-                    return_span,
-                    format!("could not fully resolve: {ty} => {err:?}"),
-                );
-                collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
-            }
-        }
-    }
-
-    Ok(&*tcx.arena.alloc(collected_tys))
-}
-
-struct ImplTraitInTraitCollector<'a, 'tcx> {
-    ocx: &'a ObligationCtxt<'a, 'tcx>,
-    types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>,
-    span: Span,
-    param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
-}
-
-impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
-    fn new(
-        ocx: &'a ObligationCtxt<'a, 'tcx>,
-        span: Span,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
-    ) -> Self {
-        ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
-    }
-}
-
-impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.ocx.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Projection, proj) = ty.kind()
-            && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
-        {
-            if let Some((ty, _)) = self.types.get(&proj.def_id) {
-                return *ty;
-            }
-            //FIXME(RPITIT): Deny nested RPITIT in substs too
-            if proj.substs.has_escaping_bound_vars() {
-                bug!("FIXME(RPITIT): error here");
-            }
-            // Replace with infer var
-            let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
-                span: self.span,
-                kind: TypeVariableOriginKind::MiscVariable,
-            });
-            self.types.insert(proj.def_id, (infer_ty, proj.substs));
-            // Recurse into bounds
-            for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
-                let pred = pred.fold_with(self);
-                let pred = self.ocx.normalize(
-                    &ObligationCause::misc(self.span, self.body_id),
-                    self.param_env,
-                    pred,
-                );
-
-                self.ocx.register_obligation(traits::Obligation::new(
-                    self.tcx(),
-                    ObligationCause::new(
-                        self.span,
-                        self.body_id,
-                        ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
-                    ),
-                    self.param_env,
-                    pred,
-                ));
-            }
-            infer_ty
-        } else {
-            ty.super_fold_with(self)
-        }
-    }
-}
-
-fn report_trait_method_mismatch<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    mut cause: ObligationCause<'tcx>,
-    terr: TypeError<'tcx>,
-    (trait_m, trait_fty): (&ty::AssocItem, Ty<'tcx>),
-    (impl_m, impl_fty): (&ty::AssocItem, Ty<'tcx>),
-    trait_sig: ty::FnSig<'tcx>,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) -> ErrorGuaranteed {
-    let tcx = infcx.tcx;
-    let (impl_err_span, trait_err_span) =
-        extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
-
-    let mut diag = struct_span_err!(
-        tcx.sess,
-        impl_err_span,
-        E0053,
-        "method `{}` has an incompatible type for trait",
-        trait_m.name
-    );
-    match &terr {
-        TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
-            if trait_m.fn_has_self_parameter =>
-        {
-            let ty = trait_sig.inputs()[0];
-            let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
-                ExplicitSelf::ByValue => "self".to_owned(),
-                ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
-                ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
-                _ => format!("self: {ty}"),
-            };
-
-            // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
-            // span points only at the type `Box<Self`>, but we want to cover the whole
-            // argument pattern and type.
-            let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                ImplItemKind::Fn(ref sig, body) => tcx
-                    .hir()
-                    .body_param_names(body)
-                    .zip(sig.decl.inputs.iter())
-                    .map(|(param, ty)| param.span.to(ty.span))
-                    .next()
-                    .unwrap_or(impl_err_span),
-                _ => bug!("{:?} is not a method", impl_m),
-            };
-
-            diag.span_suggestion(
-                span,
-                "change the self-receiver type to match the trait",
-                sugg,
-                Applicability::MachineApplicable,
-            );
-        }
-        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
-            if trait_sig.inputs().len() == *i {
-                // Suggestion to change output type. We do not suggest in `async` functions
-                // to avoid complex logic or incorrect output.
-                match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-                    ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
-                        let msg = "change the output type to match the trait";
-                        let ap = Applicability::MachineApplicable;
-                        match sig.decl.output {
-                            hir::FnRetTy::DefaultReturn(sp) => {
-                                let sugg = format!("-> {} ", trait_sig.output());
-                                diag.span_suggestion_verbose(sp, msg, sugg, ap);
-                            }
-                            hir::FnRetTy::Return(hir_ty) => {
-                                let sugg = trait_sig.output();
-                                diag.span_suggestion(hir_ty.span, msg, sugg, ap);
-                            }
-                        };
-                    }
-                    _ => {}
-                };
-            } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
-                diag.span_suggestion(
-                    impl_err_span,
-                    "change the parameter type to match the trait",
-                    trait_ty,
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-        _ => {}
-    }
-
-    cause.span = impl_err_span;
-    infcx.err_ctxt().note_type_err(
-        &mut diag,
-        &cause,
-        trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
-        Some(infer::ValuePairs::Terms(ExpectedFound {
-            expected: trait_fty.into(),
-            found: impl_fty.into(),
-        })),
-        terr,
-        false,
-        false,
-    );
-
-    return diag.emit();
-}
-
-fn check_region_bounds_on_impl_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    trait_m: &ty::AssocItem,
-    delay: bool,
-) -> Result<(), ErrorGuaranteed> {
-    let impl_generics = tcx.generics_of(impl_m.def_id);
-    let impl_params = impl_generics.own_counts().lifetimes;
-
-    let trait_generics = tcx.generics_of(trait_m.def_id);
-    let trait_params = trait_generics.own_counts().lifetimes;
-
-    debug!(
-        "check_region_bounds_on_impl_item: \
-            trait_generics={:?} \
-            impl_generics={:?}",
-        trait_generics, impl_generics
-    );
-
-    // Must have same number of early-bound lifetime parameters.
-    // Unfortunately, if the user screws up the bounds, then this
-    // will change classification between early and late.  E.g.,
-    // if in trait we have `<'a,'b:'a>`, and in impl we just have
-    // `<'a,'b>`, then we have 2 early-bound lifetime parameters
-    // in trait but 0 in the impl. But if we report "expected 2
-    // but found 0" it's confusing, because it looks like there
-    // are zero. Since I don't quite know how to phrase things at
-    // the moment, give a kind of vague error message.
-    if trait_params != impl_params {
-        let span = tcx
-            .hir()
-            .get_generics(impl_m.def_id.expect_local())
-            .expect("expected impl item to have generics or else we can't compare them")
-            .span;
-
-        let mut generics_span = None;
-        let mut bounds_span = vec![];
-        let mut where_span = None;
-        if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
-            && let Some(trait_generics) = trait_node.generics()
-        {
-            generics_span = Some(trait_generics.span);
-            // FIXME: we could potentially look at the impl's bounds to not point at bounds that
-            // *are* present in the impl.
-            for p in trait_generics.predicates {
-                if let hir::WherePredicate::BoundPredicate(pred) = p {
-                    for b in pred.bounds {
-                        if let hir::GenericBound::Outlives(lt) = b {
-                            bounds_span.push(lt.ident.span);
-                        }
-                    }
-                }
-            }
-            if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
-                && let Some(impl_generics) = impl_node.generics()
-            {
-                let mut impl_bounds = 0;
-                for p in impl_generics.predicates {
-                    if let hir::WherePredicate::BoundPredicate(pred) = p {
-                        for b in pred.bounds {
-                            if let hir::GenericBound::Outlives(_) = b {
-                                impl_bounds += 1;
-                            }
-                        }
-                    }
-                }
-                if impl_bounds == bounds_span.len() {
-                    bounds_span = vec![];
-                } else if impl_generics.has_where_clause_predicates {
-                    where_span = Some(impl_generics.where_clause_span);
-                }
-            }
-        }
-        let reported = tcx
-            .sess
-            .create_err(LifetimesOrBoundsMismatchOnTrait {
-                span,
-                item_kind: assoc_item_kind_str(impl_m),
-                ident: impl_m.ident(tcx),
-                generics_span,
-                bounds_span,
-                where_span,
-            })
-            .emit_unless(delay);
-        return Err(reported);
-    }
-
-    Ok(())
-}
-
-#[instrument(level = "debug", skip(infcx))]
-fn extract_spans_for_error_reporting<'tcx>(
-    infcx: &infer::InferCtxt<'tcx>,
-    terr: TypeError<'_>,
-    cause: &ObligationCause<'tcx>,
-    impl_m: &ty::AssocItem,
-    trait_m: &ty::AssocItem,
-) -> (Span, Option<Span>) {
-    let tcx = infcx.tcx;
-    let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-        ImplItemKind::Fn(ref sig, _) => {
-            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
-        }
-        _ => bug!("{:?} is not a method", impl_m),
-    };
-    let trait_args =
-        trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
-            TraitItemKind::Fn(ref sig, _) => {
-                sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
-            }
-            _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
-        });
-
-    match terr {
-        TypeError::ArgumentMutability(i) => {
-            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
-        }
-        TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
-            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
-        }
-        _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
-    }
-}
-
-fn compare_self_type<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    impl_m_span: Span,
-    trait_m: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
-    // Try to give more informative error messages about self typing
-    // mismatches.  Note that any mismatch will also be detected
-    // below, where we construct a canonical function type that
-    // includes the self parameter as a normal parameter.  It's just
-    // that the error messages you get out of this code are a bit more
-    // inscrutable, particularly for cases where one method has no
-    // self.
-
-    let self_string = |method: &ty::AssocItem| {
-        let untransformed_self_ty = match method.container {
-            ty::ImplContainer => impl_trait_ref.self_ty(),
-            ty::TraitContainer => tcx.types.self_param,
-        };
-        let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
-        let param_env = ty::ParamEnv::reveal_all();
-
-        let infcx = tcx.infer_ctxt().build();
-        let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
-        let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
-        match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
-            ExplicitSelf::ByValue => "self".to_owned(),
-            ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
-            ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
-            _ => format!("self: {self_arg_ty}"),
-        }
-    };
-
-    match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
-        (false, false) | (true, true) => {}
-
-        (false, true) => {
-            let self_descr = self_string(impl_m);
-            let mut err = struct_span_err!(
-                tcx.sess,
-                impl_m_span,
-                E0185,
-                "method `{}` has a `{}` declaration in the impl, but not in the trait",
-                trait_m.name,
-                self_descr
-            );
-            err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
-            if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
-                err.span_label(span, format!("trait method declared without `{self_descr}`"));
-            } else {
-                err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
-            }
-            let reported = err.emit();
-            return Err(reported);
-        }
-
-        (true, false) => {
-            let self_descr = self_string(trait_m);
-            let mut err = struct_span_err!(
-                tcx.sess,
-                impl_m_span,
-                E0186,
-                "method `{}` has a `{}` declaration in the trait, but not in the impl",
-                trait_m.name,
-                self_descr
-            );
-            err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
-            if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
-                err.span_label(span, format!("`{self_descr}` used in trait"));
-            } else {
-                err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
-            }
-            let reported = err.emit();
-            return Err(reported);
-        }
-    }
-
-    Ok(())
-}
-
-/// Checks that the number of generics on a given assoc item in a trait impl is the same
-/// as the number of generics on the respective assoc item in the trait definition.
-///
-/// For example this code emits the errors in the following code:
-/// ```
-/// trait Trait {
-///     fn foo();
-///     type Assoc<T>;
-/// }
-///
-/// impl Trait for () {
-///     fn foo<T>() {}
-///     //~^ error
-///     type Assoc = u32;
-///     //~^ error
-/// }
-/// ```
-///
-/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
-/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
-/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
-fn compare_number_of_generics<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_: &ty::AssocItem,
-    trait_: &ty::AssocItem,
-    trait_span: Option<Span>,
-    delay: bool,
-) -> Result<(), ErrorGuaranteed> {
-    let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
-    let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
-
-    // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
-    // in `compare_generic_param_kinds` which will give a nicer error message than something like:
-    // "expected 1 type parameter, found 0 type parameters"
-    if (trait_own_counts.types + trait_own_counts.consts)
-        == (impl_own_counts.types + impl_own_counts.consts)
-    {
-        return Ok(());
-    }
-
-    let matchings = [
-        ("type", trait_own_counts.types, impl_own_counts.types),
-        ("const", trait_own_counts.consts, impl_own_counts.consts),
-    ];
-
-    let item_kind = assoc_item_kind_str(impl_);
-
-    let mut err_occurred = None;
-    for (kind, trait_count, impl_count) in matchings {
-        if impl_count != trait_count {
-            let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
-                let mut spans = generics
-                    .params
-                    .iter()
-                    .filter(|p| match p.kind {
-                        hir::GenericParamKind::Lifetime {
-                            kind: hir::LifetimeParamKind::Elided,
-                        } => {
-                            // A fn can have an arbitrary number of extra elided lifetimes for the
-                            // same signature.
-                            !matches!(kind, ty::AssocKind::Fn)
-                        }
-                        _ => true,
-                    })
-                    .map(|p| p.span)
-                    .collect::<Vec<Span>>();
-                if spans.is_empty() {
-                    spans = vec![generics.span]
-                }
-                spans
-            };
-            let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
-                let trait_item = tcx.hir().expect_trait_item(def_id);
-                let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
-                let impl_trait_spans: Vec<Span> = trait_item
-                    .generics
-                    .params
-                    .iter()
-                    .filter_map(|p| match p.kind {
-                        GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
-                        _ => None,
-                    })
-                    .collect();
-                (Some(arg_spans), impl_trait_spans)
-            } else {
-                (trait_span.map(|s| vec![s]), vec![])
-            };
-
-            let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
-            let impl_item_impl_trait_spans: Vec<Span> = impl_item
-                .generics
-                .params
-                .iter()
-                .filter_map(|p| match p.kind {
-                    GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
-                    _ => None,
-                })
-                .collect();
-            let spans = arg_spans(impl_.kind, impl_item.generics);
-            let span = spans.first().copied();
-
-            let mut err = tcx.sess.struct_span_err_with_code(
-                spans,
-                &format!(
-                    "{} `{}` has {} {kind} parameter{} but its trait \
-                     declaration has {} {kind} parameter{}",
-                    item_kind,
-                    trait_.name,
-                    impl_count,
-                    pluralize!(impl_count),
-                    trait_count,
-                    pluralize!(trait_count),
-                    kind = kind,
-                ),
-                DiagnosticId::Error("E0049".into()),
-            );
-
-            let mut suffix = None;
-
-            if let Some(spans) = trait_spans {
-                let mut spans = spans.iter();
-                if let Some(span) = spans.next() {
-                    err.span_label(
-                        *span,
-                        format!(
-                            "expected {} {} parameter{}",
-                            trait_count,
-                            kind,
-                            pluralize!(trait_count),
-                        ),
-                    );
-                }
-                for span in spans {
-                    err.span_label(*span, "");
-                }
-            } else {
-                suffix = Some(format!(", expected {trait_count}"));
-            }
-
-            if let Some(span) = span {
-                err.span_label(
-                    span,
-                    format!(
-                        "found {} {} parameter{}{}",
-                        impl_count,
-                        kind,
-                        pluralize!(impl_count),
-                        suffix.unwrap_or_else(String::new),
-                    ),
-                );
-            }
-
-            for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
-                err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
-            }
-
-            let reported = err.emit_unless(delay);
-            err_occurred = Some(reported);
-        }
-    }
-
-    if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) }
-}
-
-fn compare_number_of_method_arguments<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    impl_m_span: Span,
-    trait_m: &ty::AssocItem,
-    trait_item_span: Option<Span>,
-) -> Result<(), ErrorGuaranteed> {
-    let impl_m_fty = tcx.fn_sig(impl_m.def_id);
-    let trait_m_fty = tcx.fn_sig(trait_m.def_id);
-    let trait_number_args = trait_m_fty.inputs().skip_binder().len();
-    let impl_number_args = impl_m_fty.inputs().skip_binder().len();
-    if trait_number_args != impl_number_args {
-        let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
-            match tcx.hir().expect_trait_item(def_id).kind {
-                TraitItemKind::Fn(ref trait_m_sig, _) => {
-                    let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
-                    if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
-                        Some(if pos == 0 {
-                            arg.span
-                        } else {
-                            arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
-                        })
-                    } else {
-                        trait_item_span
-                    }
-                }
-                _ => bug!("{:?} is not a method", impl_m),
-            }
-        } else {
-            trait_item_span
-        };
-        let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
-            ImplItemKind::Fn(ref impl_m_sig, _) => {
-                let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
-                if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
-                    if pos == 0 {
-                        arg.span
-                    } else {
-                        arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
-                    }
-                } else {
-                    impl_m_span
-                }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
-        };
-        let mut err = struct_span_err!(
-            tcx.sess,
-            impl_span,
-            E0050,
-            "method `{}` has {} but the declaration in trait `{}` has {}",
-            trait_m.name,
-            potentially_plural_count(impl_number_args, "parameter"),
-            tcx.def_path_str(trait_m.def_id),
-            trait_number_args
-        );
-        if let Some(trait_span) = trait_span {
-            err.span_label(
-                trait_span,
-                format!(
-                    "trait requires {}",
-                    potentially_plural_count(trait_number_args, "parameter")
-                ),
-            );
-        } else {
-            err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
-        }
-        err.span_label(
-            impl_span,
-            format!(
-                "expected {}, found {}",
-                potentially_plural_count(trait_number_args, "parameter"),
-                impl_number_args
-            ),
-        );
-        let reported = err.emit();
-        return Err(reported);
-    }
-
-    Ok(())
-}
-
-fn compare_synthetic_generics<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    trait_m: &ty::AssocItem,
-) -> Result<(), ErrorGuaranteed> {
-    // FIXME(chrisvittal) Clean up this function, list of FIXME items:
-    //     1. Better messages for the span labels
-    //     2. Explanation as to what is going on
-    // If we get here, we already have the same number of generics, so the zip will
-    // be okay.
-    let mut error_found = None;
-    let impl_m_generics = tcx.generics_of(impl_m.def_id);
-    let trait_m_generics = tcx.generics_of(trait_m.def_id);
-    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
-    });
-    let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
-    });
-    for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
-        iter::zip(impl_m_type_params, trait_m_type_params)
-    {
-        if impl_synthetic != trait_synthetic {
-            let impl_def_id = impl_def_id.expect_local();
-            let impl_span = tcx.def_span(impl_def_id);
-            let trait_span = tcx.def_span(trait_def_id);
-            let mut err = struct_span_err!(
-                tcx.sess,
-                impl_span,
-                E0643,
-                "method `{}` has incompatible signature for trait",
-                trait_m.name
-            );
-            err.span_label(trait_span, "declaration in trait here");
-            match (impl_synthetic, trait_synthetic) {
-                // The case where the impl method uses `impl Trait` but the trait method uses
-                // explicit generics
-                (true, false) => {
-                    err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
-                    (|| {
-                        // try taking the name from the trait impl
-                        // FIXME: this is obviously suboptimal since the name can already be used
-                        // as another generic argument
-                        let new_name = tcx.opt_item_name(trait_def_id)?;
-                        let trait_m = trait_m.def_id.as_local()?;
-                        let trait_m = tcx.hir().expect_trait_item(trait_m);
-
-                        let impl_m = impl_m.def_id.as_local()?;
-                        let impl_m = tcx.hir().expect_impl_item(impl_m);
-
-                        // in case there are no generics, take the spot between the function name
-                        // and the opening paren of the argument list
-                        let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
-                        // in case there are generics, just replace them
-                        let generics_span =
-                            impl_m.generics.span.substitute_dummy(new_generics_span);
-                        // replace with the generics from the trait
-                        let new_generics =
-                            tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;
-
-                        err.multipart_suggestion(
-                            "try changing the `impl Trait` argument to a generic parameter",
-                            vec![
-                                // replace `impl Trait` with `T`
-                                (impl_span, new_name.to_string()),
-                                // replace impl method generics with trait method generics
-                                // This isn't quite right, as users might have changed the names
-                                // of the generics, but it works for the common case
-                                (generics_span, new_generics),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                        Some(())
-                    })();
-                }
-                // The case where the trait method uses `impl Trait`, but the impl method uses
-                // explicit generics.
-                (false, true) => {
-                    err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
-                    (|| {
-                        let impl_m = impl_m.def_id.as_local()?;
-                        let impl_m = tcx.hir().expect_impl_item(impl_m);
-                        let input_tys = match impl_m.kind {
-                            hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
-                            _ => unreachable!(),
-                        };
-                        struct Visitor(Option<Span>, hir::def_id::LocalDefId);
-                        impl<'v> intravisit::Visitor<'v> for Visitor {
-                            fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
-                                intravisit::walk_ty(self, ty);
-                                if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
-                                    ty.kind
-                                    && let Res::Def(DefKind::TyParam, def_id) = path.res
-                                    && def_id == self.1.to_def_id()
-                                {
-                                    self.0 = Some(ty.span);
-                                }
-                            }
-                        }
-                        let mut visitor = Visitor(None, impl_def_id);
-                        for ty in input_tys {
-                            intravisit::Visitor::visit_ty(&mut visitor, ty);
-                        }
-                        let span = visitor.0?;
-
-                        let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
-                        let bounds = bounds.first()?.span().to(bounds.last()?.span());
-                        let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
-
-                        err.multipart_suggestion(
-                            "try removing the generic parameter and using `impl Trait` instead",
-                            vec![
-                                // delete generic parameters
-                                (impl_m.generics.span, String::new()),
-                                // replace param usage with `impl Trait`
-                                (span, format!("impl {bounds}")),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                        Some(())
-                    })();
-                }
-                _ => unreachable!(),
-            }
-            let reported = err.emit();
-            error_found = Some(reported);
-        }
-    }
-    if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
-}
-
-/// Checks that all parameters in the generics of a given assoc item in a trait impl have
-/// the same kind as the respective generic parameter in the trait def.
-///
-/// For example all 4 errors in the following code are emitted here:
-/// ```
-/// trait Foo {
-///     fn foo<const N: u8>();
-///     type bar<const N: u8>;
-///     fn baz<const N: u32>();
-///     type blah<T>;
-/// }
-///
-/// impl Foo for () {
-///     fn foo<const N: u64>() {}
-///     //~^ error
-///     type bar<const N: u64> {}
-///     //~^ error
-///     fn baz<T>() {}
-///     //~^ error
-///     type blah<const N: i64> = u32;
-///     //~^ error
-/// }
-/// ```
-///
-/// This function does not handle lifetime parameters
-fn compare_generic_param_kinds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_item: &ty::AssocItem,
-    trait_item: &ty::AssocItem,
-    delay: bool,
-) -> Result<(), ErrorGuaranteed> {
-    assert_eq!(impl_item.kind, trait_item.kind);
-
-    let ty_const_params_of = |def_id| {
-        tcx.generics_of(def_id).params.iter().filter(|param| {
-            matches!(
-                param.kind,
-                GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
-            )
-        })
-    };
-
-    for (param_impl, param_trait) in
-        iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
-    {
-        use GenericParamDefKind::*;
-        if match (&param_impl.kind, &param_trait.kind) {
-            (Const { .. }, Const { .. })
-                if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
-            {
-                true
-            }
-            (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
-            // this is exhaustive so that anyone adding new generic param kinds knows
-            // to make sure this error is reported for them.
-            (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
-            (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
-        } {
-            let param_impl_span = tcx.def_span(param_impl.def_id);
-            let param_trait_span = tcx.def_span(param_trait.def_id);
-
-            let mut err = struct_span_err!(
-                tcx.sess,
-                param_impl_span,
-                E0053,
-                "{} `{}` has an incompatible generic parameter for trait `{}`",
-                assoc_item_kind_str(&impl_item),
-                trait_item.name,
-                &tcx.def_path_str(tcx.parent(trait_item.def_id))
-            );
-
-            let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
-                Const { .. } => {
-                    format!("{} const parameter of type `{}`", prefix, tcx.type_of(param.def_id))
-                }
-                Type { .. } => format!("{} type parameter", prefix),
-                Lifetime { .. } => unreachable!(),
-            };
-
-            let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
-            err.span_label(trait_header_span, "");
-            err.span_label(param_trait_span, make_param_message("expected", param_trait));
-
-            let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id));
-            err.span_label(impl_header_span, "");
-            err.span_label(param_impl_span, make_param_message("found", param_impl));
-
-            let reported = err.emit_unless(delay);
-            return Err(reported);
-        }
-    }
-
-    Ok(())
-}
-
-/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
-pub(crate) fn raw_compare_const_impl(
-    tcx: TyCtxt<'_>,
-    (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
-) -> Result<(), ErrorGuaranteed> {
-    let impl_const_item = tcx.associated_item(impl_const_item_def);
-    let trait_const_item = tcx.associated_item(trait_const_item_def);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
-    debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
-
-    let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
-
-    let infcx = tcx.infer_ctxt().build();
-    let param_env = tcx.param_env(impl_const_item_def.to_def_id());
-    let ocx = ObligationCtxt::new(&infcx);
-
-    // The below is for the most part highly similar to the procedure
-    // for methods above. It is simpler in many respects, especially
-    // because we shouldn't really have to deal with lifetimes or
-    // predicates. In fact some of this should probably be put into
-    // shared functions because of DRY violations...
-    let trait_to_impl_substs = impl_trait_ref.substs;
-
-    // Create a parameter environment that represents the implementation's
-    // method.
-    let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
-
-    // Compute placeholder form of impl and trait const tys.
-    let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
-    let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
-    let mut cause = ObligationCause::new(
-        impl_c_span,
-        impl_c_hir_id,
-        ObligationCauseCode::CompareImplItemObligation {
-            impl_item_def_id: impl_const_item_def,
-            trait_item_def_id: trait_const_item_def,
-            kind: impl_const_item.kind,
-        },
-    );
-
-    // There is no "body" here, so just pass dummy id.
-    let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
-
-    debug!("compare_const_impl: impl_ty={:?}", impl_ty);
-
-    let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
-
-    debug!("compare_const_impl: trait_ty={:?}", trait_ty);
-
-    let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
-
-    if let Err(terr) = err {
-        debug!(
-            "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
-            impl_ty, trait_ty
-        );
-
-        // Locate the Span containing just the type of the offending impl
-        match tcx.hir().expect_impl_item(impl_const_item_def).kind {
-            ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
-            _ => bug!("{:?} is not a impl const", impl_const_item),
-        }
-
-        let mut diag = struct_span_err!(
-            tcx.sess,
-            cause.span,
-            E0326,
-            "implemented const `{}` has an incompatible type for trait",
-            trait_const_item.name
-        );
-
-        let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
-            // Add a label to the Span containing just the type of the const
-            match tcx.hir().expect_trait_item(trait_c_def_id).kind {
-                TraitItemKind::Const(ref ty, _) => ty.span,
-                _ => bug!("{:?} is not a trait const", trait_const_item),
-            }
-        });
-
-        infcx.err_ctxt().note_type_err(
-            &mut diag,
-            &cause,
-            trait_c_span.map(|span| (span, "type in trait".to_owned())),
-            Some(infer::ValuePairs::Terms(ExpectedFound {
-                expected: trait_ty.into(),
-                found: impl_ty.into(),
-            })),
-            terr,
-            false,
-            false,
-        );
-        return Err(diag.emit());
-    };
-
-    // Check that all obligations are satisfied by the implementation's
-    // version.
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
-    }
-
-    // FIXME return `ErrorReported` if region obligations error?
-    let outlives_environment = OutlivesEnvironment::new(param_env);
-    infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment);
-    Ok(())
-}
-
-pub(crate) fn compare_ty_impl<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_ty: &ty::AssocItem,
-    impl_ty_span: Span,
-    trait_ty: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    trait_item_span: Option<Span>,
-) {
-    debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
-
-    let _: Result<(), ErrorGuaranteed> = (|| {
-        compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
-
-        compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
-
-        let sp = tcx.def_span(impl_ty.def_id);
-        compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
-
-        check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
-    })();
-}
-
-/// The equivalent of [compare_predicate_entailment], but for associated types
-/// instead of associated functions.
-fn compare_type_predicate_entailment<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_ty: &ty::AssocItem,
-    impl_ty_span: Span,
-    trait_ty: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
-    let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
-    let trait_to_impl_substs =
-        impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
-
-    let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
-    let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
-
-    check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
-
-    let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
-
-    if impl_ty_own_bounds.is_empty() {
-        // Nothing to check.
-        return Ok(());
-    }
-
-    // This `HirId` should be used for the `body_id` field on each
-    // `ObligationCause` (and the `FnCtxt`). This is what
-    // `regionck_item` expects.
-    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
-    debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
-
-    // The predicates declared by the impl definition, the trait and the
-    // associated type in the trait are assumed.
-    let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
-    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-    hybrid_preds
-        .predicates
-        .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
-
-    debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
-
-    let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
-    let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
-        Reveal::UserFacing,
-        hir::Constness::NotConst,
-    );
-    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
-    let infcx = tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(&infcx);
-
-    debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
-
-    assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
-    for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
-    {
-        let cause = ObligationCause::misc(span, impl_ty_hir_id);
-        let predicate = ocx.normalize(&cause, param_env, predicate);
-
-        let cause = ObligationCause::new(
-            span,
-            impl_ty_hir_id,
-            ObligationCauseCode::CompareImplItemObligation {
-                impl_item_def_id: impl_ty.def_id.expect_local(),
-                trait_item_def_id: trait_ty.def_id,
-                kind: impl_ty.kind,
-            },
-        );
-        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
-    }
-
-    // Check that all obligations are satisfied by the implementation's
-    // version.
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-        return Err(reported);
-    }
-
-    // Finally, resolve all regions. This catches wily misuses of
-    // lifetime parameters.
-    let outlives_environment = OutlivesEnvironment::new(param_env);
-    infcx.check_region_obligations_and_report_errors(
-        impl_ty.def_id.expect_local(),
-        &outlives_environment,
-    );
-
-    Ok(())
-}
-
-/// Validate that `ProjectionCandidate`s created for this associated type will
-/// be valid.
-///
-/// Usually given
-///
-/// trait X { type Y: Copy } impl X for T { type Y = S; }
-///
-/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
-/// impl is well-formed we have to prove `S: Copy`.
-///
-/// For default associated types the normalization is not possible (the value
-/// from the impl could be overridden). We also can't normalize generic
-/// associated types (yet) because they contain bound parameters.
-#[instrument(level = "debug", skip(tcx))]
-pub fn check_type_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ty: &ty::AssocItem,
-    impl_ty: &ty::AssocItem,
-    impl_ty_span: Span,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
-    // Given
-    //
-    // impl<A, B> Foo<u32> for (A, B) {
-    //     type Bar<C> =...
-    // }
-    //
-    // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
-    // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
-    // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
-    //    the *trait* with the generic associated type parameters (as bound vars).
-    //
-    // A note regarding the use of bound vars here:
-    // Imagine as an example
-    // ```
-    // trait Family {
-    //     type Member<C: Eq>;
-    // }
-    //
-    // impl Family for VecFamily {
-    //     type Member<C: Eq> = i32;
-    // }
-    // ```
-    // Here, we would generate
-    // ```notrust
-    // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
-    // ```
-    // when we really would like to generate
-    // ```notrust
-    // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
-    // ```
-    // But, this is probably fine, because although the first clause can be used with types C that
-    // do not implement Eq, for it to cause some kind of problem, there would have to be a
-    // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
-    // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
-    // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
-    // the trait (notably, that X: Eq and T: Family).
-    let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
-    let mut substs = smallvec::SmallVec::with_capacity(defs.count());
-    if let Some(def_id) = defs.parent {
-        let parent_defs = tcx.generics_of(def_id);
-        InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
-            tcx.mk_param_from_def(param)
-        });
-    }
-    let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
-        smallvec::SmallVec::with_capacity(defs.count());
-    InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
-        GenericParamDefKind::Type { .. } => {
-            let kind = ty::BoundTyKind::Param(param.name);
-            let bound_var = ty::BoundVariableKind::Ty(kind);
-            bound_vars.push(bound_var);
-            tcx.mk_ty(ty::Bound(
-                ty::INNERMOST,
-                ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
-            ))
-            .into()
-        }
-        GenericParamDefKind::Lifetime => {
-            let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
-            let bound_var = ty::BoundVariableKind::Region(kind);
-            bound_vars.push(bound_var);
-            tcx.mk_region(ty::ReLateBound(
-                ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
-            ))
-            .into()
-        }
-        GenericParamDefKind::Const { .. } => {
-            let bound_var = ty::BoundVariableKind::Const;
-            bound_vars.push(bound_var);
-            tcx.mk_const(
-                ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
-                tcx.type_of(param.def_id),
-            )
-            .into()
-        }
-    });
-    let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
-    let impl_ty_substs = tcx.intern_substs(&substs);
-    let container_id = impl_ty.container_id(tcx);
-
-    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
-    let impl_ty_value = tcx.type_of(impl_ty.def_id);
-
-    let param_env = tcx.param_env(impl_ty.def_id);
-
-    // When checking something like
-    //
-    // trait X { type Y: PartialEq<<Self as X>::Y> }
-    // impl X for T { default type Y = S; }
-    //
-    // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
-    // we want <T as X>::Y to normalize to S. This is valid because we are
-    // checking the default value specifically here. Add this equality to the
-    // ParamEnv for normalization specifically.
-    let normalize_param_env = {
-        let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
-        match impl_ty_value.kind() {
-            ty::Alias(ty::Projection, proj)
-                if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
-            {
-                // Don't include this predicate if the projected type is
-                // exactly the same as the projection. This can occur in
-                // (somewhat dubious) code like this:
-                //
-                // impl<T> X for T where T: X { type Y = <T as X>::Y; }
-            }
-            _ => predicates.push(
-                ty::Binder::bind_with_vars(
-                    ty::ProjectionPredicate {
-                        projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
-                        term: impl_ty_value.into(),
-                    },
-                    bound_vars,
-                )
-                .to_predicate(tcx),
-            ),
-        };
-        ty::ParamEnv::new(
-            tcx.intern_predicates(&predicates),
-            Reveal::UserFacing,
-            param_env.constness(),
-        )
-    };
-    debug!(?normalize_param_env);
-
-    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
-    let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
-    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
-
-    let infcx = tcx.infer_ctxt().build();
-    let ocx = ObligationCtxt::new(&infcx);
-
-    let assumed_wf_types =
-        ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
-
-    let normalize_cause = ObligationCause::new(
-        impl_ty_span,
-        impl_ty_hir_id,
-        ObligationCauseCode::CheckAssociatedTypeBounds {
-            impl_item_def_id: impl_ty.def_id.expect_local(),
-            trait_item_def_id: trait_ty.def_id,
-        },
-    );
-    let mk_cause = |span: Span| {
-        let code = if span.is_dummy() {
-            traits::ItemObligation(trait_ty.def_id)
-        } else {
-            traits::BindingObligation(trait_ty.def_id, span)
-        };
-        ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
-    };
-
-    let obligations = tcx
-        .bound_explicit_item_bounds(trait_ty.def_id)
-        .subst_iter_copied(tcx, rebased_substs)
-        .map(|(concrete_ty_bound, span)| {
-            debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-            traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
-        })
-        .collect();
-    debug!("check_type_bounds: item_bounds={:?}", obligations);
-
-    for mut obligation in util::elaborate_obligations(tcx, obligations) {
-        let normalized_predicate =
-            ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
-        debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
-        obligation.predicate = normalized_predicate;
-
-        ocx.register_obligation(obligation);
-    }
-    // Check that all obligations are satisfied by the implementation's
-    // version.
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-        return Err(reported);
-    }
-
-    // Finally, resolve all regions. This catches wily misuses of
-    // lifetime parameters.
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
-    let outlives_environment =
-        OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
-
-    infcx.check_region_obligations_and_report_errors(
-        impl_ty.def_id.expect_local(),
-        &outlives_environment,
-    );
-
-    let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-    for (key, value) in constraints {
-        infcx
-            .err_ctxt()
-            .report_mismatched_types(
-                &ObligationCause::misc(
-                    value.hidden_type.span,
-                    tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
-                ),
-                tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
-                value.hidden_type.ty,
-                TypeError::Mismatch,
-            )
-            .emit();
-    }
-
-    Ok(())
-}
-
-fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
-    match impl_item.kind {
-        ty::AssocKind::Const => "const",
-        ty::AssocKind::Fn => "method",
-        ty::AssocKind::Type => "type",
-    }
-}
index ed2aed293a7710218016b653a028db52f5a9ff9d..382c3f5294511a40c364060f7b050773bcad737f 100644 (file)
@@ -63,7 +63,7 @@
 */
 
 mod check;
-mod compare_method;
+mod compare_impl_item;
 pub mod dropck;
 pub mod intrinsic;
 pub mod intrinsicck;
@@ -94,7 +94,7 @@
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::compare_method::collect_trait_impl_trait_tys;
+use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
 use self::region::region_scope_tree;
 
 pub fn provide(providers: &mut Providers) {
@@ -103,8 +103,8 @@ pub fn provide(providers: &mut Providers) {
         adt_destructor,
         check_mod_item_types,
         region_scope_tree,
-        collect_trait_impl_trait_tys,
-        compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
+        collect_return_position_impl_trait_in_trait_tys,
+        compare_impl_const: compare_impl_item::compare_impl_const_raw,
         ..*providers
     };
 }
index 4f27068429c6d0777f96c8d3f479b408c3d95f03..e9baab594530ececae99c5e959b0bd7b1b5eeaa6 100644 (file)
@@ -97,25 +97,28 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     let infcx = &tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new(infcx);
 
-    let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
-
     let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
 
     if !tcx.features().trivial_bounds {
         wfcx.check_false_global_bounds()
     }
     f(&mut wfcx);
+
+    let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
         infcx.err_ctxt().report_fulfillment_errors(&errors, None);
         return;
     }
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
     let outlives_environment =
         OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
 
-    infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
+    let _ = infcx
+        .err_ctxt()
+        .check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
 }
 
 fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
@@ -291,7 +294,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
         // Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
         if let Some(hir::FnSig { decl, span, .. }) = method_sig {
             if let [self_ty, _] = decl.inputs {
-                if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+                if !matches!(self_ty.kind, hir::TyKind::Ref(_, _)) {
                     tcx.sess
                         .struct_span_err(
                             self_ty.span,
@@ -1489,54 +1492,38 @@ fn check_fn_or_method<'tcx>(
     def_id: LocalDefId,
 ) {
     let tcx = wfcx.tcx();
-    let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
+    let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
 
     // Normalize the input and output types one at a time, using a different
     // `WellFormedLoc` for each. We cannot call `normalize_associated_types`
     // on the entire `FnSig`, since this would use the same `WellFormedLoc`
     // for each type, preventing the HIR wf check from generating
     // a nice error message.
-    let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig;
-    inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| {
-        wfcx.normalize(
-            span,
-            Some(WellFormedLoc::Param {
-                function: def_id,
-                // Note that the `param_idx` of the output type is
-                // one greater than the index of the last input type.
-                param_idx: i.try_into().unwrap(),
-            }),
-            ty,
-        )
-    }));
-    // Manually call `normalize_associated_types_in` on the other types
-    // in `FnSig`. This ensures that if the types of these fields
-    // ever change to include projections, we will start normalizing
-    // them automatically.
-    let sig = ty::FnSig {
-        inputs_and_output,
-        c_variadic: wfcx.normalize(span, None, c_variadic),
-        unsafety: wfcx.normalize(span, None, unsafety),
-        abi: wfcx.normalize(span, None, abi),
-    };
+    let arg_span =
+        |idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span);
+
+    sig.inputs_and_output =
+        tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
+            wfcx.normalize(
+                arg_span(idx),
+                Some(WellFormedLoc::Param {
+                    function: def_id,
+                    // Note that the `param_idx` of the output type is
+                    // one greater than the index of the last input type.
+                    param_idx: idx.try_into().unwrap(),
+                }),
+                ty,
+            )
+        }));
 
-    for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() {
+    for (idx, ty) in sig.inputs_and_output.iter().enumerate() {
         wfcx.register_wf_obligation(
-            ty.span,
-            Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
-            input_ty.into(),
+            arg_span(idx),
+            Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }),
+            ty.into(),
         );
     }
 
-    wfcx.register_wf_obligation(
-        hir_decl.output.span(),
-        Some(WellFormedLoc::Param {
-            function: def_id,
-            param_idx: sig.inputs().len().try_into().unwrap(),
-        }),
-        sig.output().into(),
-    );
-
     check_where_clauses(wfcx, span, def_id);
 
     check_return_position_impl_trait_in_trait_bounds(
@@ -1912,7 +1899,7 @@ fn check_false_global_bounds(&mut self) {
             }
             let pred = obligation.predicate;
             // Match the existing behavior.
-            if pred.is_global() && !pred.has_late_bound_regions() {
+            if pred.is_global() && !pred.has_late_bound_vars() {
                 let pred = self.normalize(span, None, pred);
                 let hir_node = tcx.hir().find(self.body_id);
 
index 2790d91572becae4c81abe75a32371ce804ff0d2..2e2c1591e9b4472dffb5e39a22b33b92685fbbc7 100644 (file)
@@ -325,7 +325,9 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
 
                 // Finally, resolve all regions.
                 let outlives_env = OutlivesEnvironment::new(param_env);
-                infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+                let _ = infcx
+                    .err_ctxt()
+                    .check_region_obligations_and_report_errors(impl_did, &outlives_env);
             }
         }
         _ => {
@@ -565,7 +567,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
     // Finally, resolve all regions.
     let outlives_env = OutlivesEnvironment::new(param_env);
-    infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+    let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl_did, &outlives_env);
 
     CoerceUnsizedInfo { custom_kind: kind }
 }
index c6d4aeefc80e5e7883862065b6b6fe5fd63ba6d0..e8b3f139623ed56ce750a81dc1a6765f0fc2fd62 100644 (file)
@@ -53,7 +53,7 @@ fn do_orphan_check_impl<'tcx>(
             sp,
             item.span,
             tr.path.span,
-            trait_ref.self_ty(),
+            trait_ref,
             impl_.self_ty.span,
             &impl_.generics,
             err,
@@ -154,11 +154,12 @@ fn emit_orphan_check_error<'tcx>(
     sp: Span,
     full_impl_span: Span,
     trait_span: Span,
-    self_ty: Ty<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
     self_ty_span: Span,
     generics: &hir::Generics<'tcx>,
     err: traits::OrphanCheckErr<'tcx>,
 ) -> Result<!, ErrorGuaranteed> {
+    let self_ty = trait_ref.self_ty();
     Err(match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
             let msg = match self_ty.kind() {
@@ -187,7 +188,14 @@ fn emit_orphan_check_error<'tcx>(
                 let msg = |ty: &str, postfix: &str| {
                     format!("{ty} is not defined in the current crate{postfix}")
                 };
-                let this = |name: &str| msg("this", &format!(" because {name} are always foreign"));
+
+                let this = |name: &str| {
+                    if !trait_ref.def_id.is_local() && !is_target_ty {
+                        msg("this", &format!(" because this is a foreign trait"))
+                    } else {
+                        msg("this", &format!(" because {name} are always foreign"))
+                    }
+                };
                 let msg = match &ty.kind() {
                     ty::Slice(_) => this("slices"),
                     ty::Array(..) => this("arrays"),
index a34815b45b3adeb7834cc163c66bbd5cbc7257fc..70cc15b2f8c543268f926a32ff79ea330acce294 100644 (file)
@@ -21,7 +21,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
                 struct_span_err!(
                     tcx.sess,
-                    item.span,
+                    tcx.def_span(def_id),
                     E0199,
                     "implementing the trait `{}` is not unsafe",
                     trait_ref.print_only_trait_path()
@@ -38,7 +38,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
                 struct_span_err!(
                     tcx.sess,
-                    item.span,
+                    tcx.def_span(def_id),
                     E0200,
                     "the trait `{}` requires an `unsafe impl` declaration",
                     trait_ref.print_only_trait_path()
@@ -61,7 +61,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
                 struct_span_err!(
                     tcx.sess,
-                    item.span,
+                    tcx.def_span(def_id),
                     E0569,
                     "requires an `unsafe impl` declaration due to `#[{}]` attribute",
                     attr_name
index b7d599f57fd449136dd6e81d461ac269fba5b5bb..b7f259668a1e48f005761958a12947e6986d77ea 100644 (file)
@@ -17,6 +17,7 @@
 use crate::astconv::AstConv;
 use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::errors;
+use hir::def::DefKind;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
@@ -24,6 +25,8 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericParamKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -31,7 +34,9 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+use rustc_trait_selection::traits::ObligationCtxt;
 use std::iter;
 
 mod generics_of;
@@ -208,7 +213,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
             is_fn = true;
 
             // Check if parent is const or static
-            let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id);
+            let parent_id = tcx.hir().parent_id(hir_ty.hir_id);
             let parent_node = tcx.hir().get(parent_id);
 
             is_const_or_static = matches!(
@@ -500,9 +505,9 @@ fn projected_ty_from_poly_trait_ref(
         }
     }
 
-    fn normalize_ty(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        // Types in item signatures are not normalized to avoid undue dependencies.
-        ty
+    fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
+        // FIXME(#103640): Should we handle the case where `ty` is a projection?
+        ty.ty_adt_def()
     }
 
     fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
@@ -1059,7 +1064,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
             is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
         }
         Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
-        Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
+        Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
         OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
         Path(hir::QPath::TypeRelative(ty, segment)) => {
             is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
@@ -1104,7 +1109,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
             // Do not try to infer the return type for a impl method coming from a trait
             if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
-                tcx.hir().get(tcx.hir().get_parent_node(hir_id))
+                tcx.hir().get_parent(hir_id)
                 && i.of_trait.is_some()
             {
                 <dyn AstConv<'_>>::ty_of_fn(
@@ -1191,12 +1196,11 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                 ty::ReErased => tcx.lifetimes.re_static,
                 _ => r,
             });
-            let fn_sig = ty::Binder::dummy(fn_sig);
 
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_ty(ty);
             let mut diag = bad_placeholder(tcx, visitor.0, "return type");
-            let ret_ty = fn_sig.skip_binder().output();
+            let ret_ty = fn_sig.output();
             if ret_ty.is_suggestable(tcx, false) {
                 diag.span_suggestion(
                     ty.span,
@@ -1219,16 +1223,26 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                         Applicability::MachineApplicable,
                     );
                 }
+            } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) {
+                diag.span_suggestion(
+                    ty.span,
+                    "replace with an appropriate return type",
+                    sugg,
+                    Applicability::MachineApplicable,
+                );
             } else if ret_ty.is_closure() {
-                // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
-                // to prevent the user from getting a papercut while trying to use the unique closure
-                // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
                 diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
-                diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+            }
+            // Also note how `Fn` traits work just in case!
+            if ret_ty.is_closure() {
+                diag.note(
+                    "for more information on `Fn` traits and closure types, see \
+                     https://doc.rust-lang.org/book/ch13-01-closures.html",
+                );
             }
             diag.emit();
 
-            fn_sig
+            ty::Binder::dummy(fn_sig)
         }
         None => <dyn AstConv<'_>>::ty_of_fn(
             icx,
@@ -1242,6 +1256,98 @@ fn infer_return_ty_for_fn_sig<'tcx>(
     }
 }
 
+fn suggest_impl_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ret_ty: Ty<'tcx>,
+    span: Span,
+    hir_id: hir::HirId,
+    def_id: LocalDefId,
+) -> Option<String> {
+    let format_as_assoc: fn(_, _, _, _, _) -> _ =
+        |tcx: TyCtxt<'tcx>,
+         _: ty::SubstsRef<'tcx>,
+         trait_def_id: DefId,
+         assoc_item_def_id: DefId,
+         item_ty: Ty<'tcx>| {
+            let trait_name = tcx.item_name(trait_def_id);
+            let assoc_name = tcx.item_name(assoc_item_def_id);
+            Some(format!("impl {trait_name}<{assoc_name} = {item_ty}>"))
+        };
+    let format_as_parenthesized: fn(_, _, _, _, _) -> _ =
+        |tcx: TyCtxt<'tcx>,
+         substs: ty::SubstsRef<'tcx>,
+         trait_def_id: DefId,
+         _: DefId,
+         item_ty: Ty<'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 maybe_ret =
+                if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
+            Some(format!(
+                "impl {trait_name}({}){maybe_ret}",
+                types.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ")
+            ))
+        };
+
+    for (trait_def_id, assoc_item_def_id, formatter) in [
+        (
+            tcx.get_diagnostic_item(sym::Iterator),
+            tcx.get_diagnostic_item(sym::IteratorItem),
+            format_as_assoc,
+        ),
+        (
+            tcx.lang_items().future_trait(),
+            tcx.get_diagnostic_item(sym::FutureOutput),
+            format_as_assoc,
+        ),
+        (tcx.lang_items().fn_trait(), tcx.lang_items().fn_once_output(), format_as_parenthesized),
+        (
+            tcx.lang_items().fn_mut_trait(),
+            tcx.lang_items().fn_once_output(),
+            format_as_parenthesized,
+        ),
+        (
+            tcx.lang_items().fn_once_trait(),
+            tcx.lang_items().fn_once_output(),
+            format_as_parenthesized,
+        ),
+    ] {
+        let Some(trait_def_id) = trait_def_id else { continue; };
+        let Some(assoc_item_def_id) = assoc_item_def_id else { continue; };
+        if tcx.def_kind(assoc_item_def_id) != DefKind::AssocTy {
+            continue;
+        }
+        let param_env = tcx.param_env(def_id);
+        let infcx = tcx.infer_ctxt().build();
+        let substs = ty::InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
+            if param.index == 0 { ret_ty.into() } else { infcx.var_for_def(span, param) }
+        });
+        if !infcx.type_implements_trait(trait_def_id, substs, param_env).must_apply_modulo_regions()
+        {
+            continue;
+        }
+        let ocx = ObligationCtxt::new_in_snapshot(&infcx);
+        let item_ty = ocx.normalize(
+            &ObligationCause::misc(span, hir_id),
+            param_env,
+            tcx.mk_projection(assoc_item_def_id, substs),
+        );
+        // 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(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(substs), trait_def_id, assoc_item_def_id, item_ty)
+        {
+            return Some(sugg);
+        }
+    }
+    None
+}
+
 fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir().expect_item(def_id.expect_local());
index cb4c35c0ce177e527e1bab8feba86b319ce53878..96221c3e3d86e1326c0ab330f7c847b820bb8ec1 100644 (file)
@@ -103,7 +103,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 // `min_const_generics`.
                 Some(parent_def_id.to_def_id())
             } else {
-                let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+                let parent_node = tcx.hir().get_parent(hir_id);
                 match parent_node {
                     // HACK(eddyb) this provides the correct generics for repeat
                     // expressions' count (i.e. `N` in `[x; N]`), and explicit
@@ -320,7 +320,7 @@ enum Defaults {
 
     // provide junk type parameter defs for const blocks.
     if let Node::AnonConst(_) = node {
-        let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+        let parent_node = tcx.hir().get_parent(hir_id);
         if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
             params.push(ty::GenericParamDef {
                 index: next_index(),
index 0542e2c8f50818fe047d605ec164543e37785062..093e9560ccdfedc408aff716744dca3c48cc909a 100644 (file)
@@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>(
     let icx = ItemCtxt::new(tcx, assoc_item_def_id);
     let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
     // Associated types are implicitly sized unless a `?Sized` bound is found
-    <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+    <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
 
     let trait_def_id = tcx.parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
@@ -44,9 +44,7 @@ fn associated_type_bounds<'tcx>(
         }
     });
 
-    let all_bounds = tcx
-        .arena
-        .alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
+    let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent));
     debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
     all_bounds
 }
@@ -74,10 +72,10 @@ fn opaque_type_bounds<'tcx>(
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
-        <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+        <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
         debug!(?bounds);
 
-        tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
+        tcx.arena.alloc_from_iter(bounds.predicates())
     })
 }
 
index b63a8ef698d1843f77021a8197e5c57ee14bd022..35f10dc873745f59d4355f1ebe675890f468f0b7 100644 (file)
@@ -617,7 +617,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     LifetimeName::Error => {}
                 }
             }
-            hir::TyKind::Rptr(ref lifetime_ref, ref mt) => {
+            hir::TyKind::Ref(ref lifetime_ref, ref mt) => {
                 self.visit_lifetime(lifetime_ref);
                 let scope = Scope::ObjectLifetimeDefault {
                     lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
@@ -682,7 +682,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     };
                     let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
                     // Ensure that the parent of the def is an item, not HRTB
-                    let parent_id = self.tcx.hir().get_parent_node(hir_id);
+                    let parent_id = self.tcx.hir().parent_id(hir_id);
                     if !parent_id.is_owner() {
                         struct_span_err!(
                             self.tcx.sess,
@@ -1195,8 +1195,10 @@ fn resolve_lifetime_ref(
                     // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
                     // regular fns.
                     if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
-                        && let hir::LifetimeName::Param(_) = lifetime_ref.res
-                        && lifetime_ref.is_anonymous()
+                        && let hir::LifetimeName::Param(param_id) = lifetime_ref.res
+                        && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
+                        && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
+                        && param.is_elided_lifetime()
                         && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
                         && !self.tcx.features().anonymous_lifetime_in_impl_trait
                     {
index 0943350e2d47c8431c97132a85fe6f844a356b27..18fc43ce15cbd4794c5f9d84273a8a4f748ff72f 100644 (file)
@@ -165,12 +165,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                 <dyn AstConv<'_>>::add_implicitly_sized(
                     &icx,
                     &mut bounds,
+                    param_ty,
                     &[],
                     Some((param.def_id, ast_generics.predicates)),
                     param.span,
                 );
                 trace!(?bounds);
-                predicates.extend(bounds.predicates(tcx, param_ty));
+                predicates.extend(bounds.predicates());
                 trace!(?predicates);
             }
             GenericParamKind::Const { .. } => {
@@ -217,7 +218,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                     &mut bounds,
                     bound_vars,
                 );
-                predicates.extend(bounds.predicates(tcx, ty));
+                predicates.extend(bounds.predicates());
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -270,7 +271,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     // We create bi-directional Outlives predicates between the original
     // and the duplicated parameter, to ensure that they do not get out of sync.
     if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
-        let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
+        let opaque_ty_id = tcx.hir().parent_id(hir_id);
         let opaque_ty_node = tcx.hir().get(opaque_ty_id);
         let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
             bug!("unexpected {opaque_ty_node:?}")
@@ -536,7 +537,7 @@ pub(super) fn super_predicates_that_define_assoc_type(
             <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
         };
 
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+        let superbounds1 = superbounds1.predicates();
 
         // Convert any explicit superbounds in the where-clause,
         // e.g., `trait Foo where Self: Bar`.
@@ -745,5 +746,5 @@ fn predicates_from_bound<'tcx>(
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     let mut bounds = Bounds::default();
     astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
-    bounds.predicates(astconv.tcx(), param_ty).collect()
+    bounds.predicates().collect()
 }
index b678990f94e918ba6f9f26ad160b9771b19366b7..1f9a9f80302e3590957b9ef5a7d466ddfd860c1e 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirId, Node};
 use rustc_middle::hir::nested_filter;
+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};
@@ -27,7 +28,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
         _ => return None,
     };
 
-    let parent_node_id = tcx.hir().get_parent_node(hir_id);
+    let parent_node_id = tcx.hir().parent_id(hir_id);
     let parent_node = tcx.hir().get(parent_node_id);
 
     let (generics, arg_idx) = match parent_node {
@@ -401,7 +402,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
         }
 
         Node::AnonConst(_) => {
-            let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+            let parent_node = tcx.hir().get_parent(hir_id);
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
                 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
@@ -444,7 +445,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         ..
                     },
                 ) if let Node::TraitRef(trait_ref) =
-                    tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+                    tcx.hir().get_parent(binding_id)
                     && e.hir_id == hir_id =>
                 {
                     let Some(trait_def_id) = trait_ref.trait_def_id() else {
@@ -471,7 +472,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 Node::TypeBinding(
                     binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. },
                 ) if let Node::TraitRef(trait_ref) =
-                    tcx.hir().get(tcx.hir().get_parent_node(binding_id))
+                    tcx.hir().get_parent(binding_id)
                     && let Some((idx, _)) =
                         gen_args.args.iter().enumerate().find(|(_, arg)| {
                             if let GenericArg::Const(ct) = arg {
@@ -907,10 +908,10 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    err.span_note(
+                    with_forced_trimmed_paths!(err.span_note(
                         tcx.hir().body(body_id).value.span,
-                        &format!("however, the inferred type `{}` cannot be named", ty),
-                    );
+                        &format!("however, the inferred type `{ty}` cannot be named"),
+                    ));
                 }
             }
 
@@ -931,10 +932,10 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    diag.span_note(
+                    with_forced_trimmed_paths!(diag.span_note(
                         tcx.hir().body(body_id).value.span,
-                        &format!("however, the inferred type `{}` cannot be named", ty),
-                    );
+                        &format!("however, the inferred type `{ty}` cannot be named"),
+                    ));
                 }
             }
 
index b60fc276178b396204208118750ca7434fa54976..8b9034d9620e2c3debfefc0081b6f3fdcf4217c9 100644 (file)
@@ -81,7 +81,6 @@
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
-use tracing::instrument;
 
 pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
     if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
@@ -182,7 +181,8 @@ fn get_impl_substs(
 
     let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
-    infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
+    let _ =
+        infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
         let span = tcx.def_span(impl1_def_id);
         tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
index 4451db19f5c1e16be69603c89b1821fe7e2e1632..574b1e8b485afad6ffc8d1ada76b48f564d73786 100644 (file)
@@ -597,11 +597,15 @@ fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) {
                 let span = self.path_segment.ident.span;
 
                 // insert a suggestion of the form "Y<'a, 'b>"
-                let ident = self.path_segment.ident.name.to_ident_string();
-                let sugg = format!("{}<{}>", ident, suggested_args);
+                let sugg = format!("<{}>", suggested_args);
                 debug!("sugg: {:?}", sugg);
 
-                err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    &msg,
+                    sugg,
+                    Applicability::HasPlaceholders,
+                );
             }
 
             AngleBrackets::Available => {
@@ -643,11 +647,15 @@ fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
                 let span = self.path_segment.ident.span;
 
                 // insert a suggestion of the form "Y<T, U>"
-                let ident = self.path_segment.ident.name.to_ident_string();
-                let sugg = format!("{}<{}>", ident, suggested_args);
+                let sugg = format!("<{}>", suggested_args);
                 debug!("sugg: {:?}", sugg);
 
-                err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    &msg,
+                    sugg,
+                    Applicability::HasPlaceholders,
+                );
             }
             AngleBrackets::Available => {
                 let gen_args_span = self.gen_args.span().unwrap();
@@ -716,7 +724,7 @@ fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) {
             num = num_trait_generics_except_self,
         );
 
-        if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id)
+        if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
         && let Some(parent_node) = self.tcx.hir().find(parent_node)
         && let hir::Node::Expr(expr) = parent_node {
             match expr.kind {
index 29a6902ccb0772591f896c431ec61e9d45ce37e1..3e3af8395a1119e65afb8a2286df07e9785e624b 100644 (file)
@@ -307,7 +307,7 @@ pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
                 self.word("*");
                 self.print_mt(mt, true);
             }
-            hir::TyKind::Rptr(ref lifetime, ref mt) => {
+            hir::TyKind::Ref(ref lifetime, ref mt) => {
                 self.word("&");
                 self.print_opt_lifetime(lifetime);
                 self.print_mt(mt, false);
@@ -1268,7 +1268,7 @@ enum AsmArg<'a> {
                 hir::InlineAsmOperand::In { reg, ref expr } => {
                     s.word("in");
                     s.popen();
-                    s.word(format!("{}", reg));
+                    s.word(format!("{reg}"));
                     s.pclose();
                     s.space();
                     s.print_expr(expr);
@@ -1276,7 +1276,7 @@ enum AsmArg<'a> {
                 hir::InlineAsmOperand::Out { reg, late, ref expr } => {
                     s.word(if late { "lateout" } else { "out" });
                     s.popen();
-                    s.word(format!("{}", reg));
+                    s.word(format!("{reg}"));
                     s.pclose();
                     s.space();
                     match expr {
@@ -1287,7 +1287,7 @@ enum AsmArg<'a> {
                 hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
                     s.word(if late { "inlateout" } else { "inout" });
                     s.popen();
-                    s.word(format!("{}", reg));
+                    s.word(format!("{reg}"));
                     s.pclose();
                     s.space();
                     s.print_expr(expr);
@@ -1295,7 +1295,7 @@ enum AsmArg<'a> {
                 hir::InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
                     s.word(if late { "inlateout" } else { "inout" });
                     s.popen();
-                    s.word(format!("{}", reg));
+                    s.word(format!("{reg}"));
                     s.pclose();
                     s.space();
                     s.print_expr(in_expr);
index ab12cae4e2b08a0b48fc57e8b687f841b7b59509..b6f19d3cc684ae1d84fc97b0c1f3fd390af54975 100644 (file)
@@ -224,14 +224,12 @@ fn suggest_removing_semicolon_for_coerce(
         let mut ret_span: MultiSpan = semi_span.into();
         ret_span.push_span_label(
             expr.span,
-            "this could be implicitly returned but it is a statement, not a \
-                            tail expression",
+            "this could be implicitly returned but it is a statement, not a tail expression",
         );
         ret_span.push_span_label(ret, "the `match` arms can conform to this return type");
         ret_span.push_span_label(
             semi_span,
-            "the `match` is a statement because of this semicolon, consider \
-                            removing it",
+            "the `match` is a statement because of this semicolon, consider removing it",
         );
         diag.span_note(ret_span, "you might have meant to return the `match` expression");
         diag.tool_only_span_suggestion(
@@ -289,15 +287,12 @@ pub(super) fn if_fallback_coercion<T>(
 
     fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
         let node = {
-            let rslt = self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(hir_id));
+            let rslt = self.tcx.hir().parent_id(self.tcx.hir().parent_id(hir_id));
             self.tcx.hir().get(rslt)
         };
         if let hir::Node::Block(block) = node {
             // check that the body's parent is an fn
-            let parent = self
-                .tcx
-                .hir()
-                .get(self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(block.hir_id)));
+            let parent = self.tcx.hir().get_parent(self.tcx.hir().parent_id(block.hir_id));
             if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) =
                 (&block.expr, parent)
             {
@@ -526,7 +521,6 @@ pub(crate) fn opt_suggest_box_span(
                         None
                     }
                 })?;
-                let opaque_ty = self.tcx.mk_opaque(rpit_def_id, substs);
 
                 if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) {
                     return None;
@@ -540,13 +534,22 @@ pub(crate) fn opt_suggest_box_span(
                     {
                         let pred = pred.kind().rebind(match pred.kind().skip_binder() {
                             ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
-                                assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
+                                // FIXME(rpitit): This will need to be fixed when we move to associated types
+                                assert!(matches!(
+                                    *trait_pred.trait_ref.self_ty().kind(),
+                                    ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+                                    if def_id == rpit_def_id && substs == substs
+                                ));
                                 ty::PredicateKind::Clause(ty::Clause::Trait(
                                     trait_pred.with_self_ty(self.tcx, ty),
                                 ))
                             }
                             ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
-                                assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
+                                assert!(matches!(
+                                    *proj_pred.projection_ty.self_ty().kind(),
+                                    ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+                                    if def_id == rpit_def_id && substs == substs
+                                ));
                                 proj_pred = proj_pred.with_self_ty(self.tcx, ty);
                                 ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
                             }
index af14ee08a9981bd187a89ee1bdb1365a053a7aaa..2cb976f718c22b72d16640e6b98e9bace72c549f 100644 (file)
@@ -241,7 +241,7 @@ fn try_overloaded_call_traits(
             });
 
             if let Some(ok) = self.lookup_method_in_trait(
-                call_expr.span,
+                self.misc(call_expr.span),
                 method_name,
                 trait_def_id,
                 adjusted_ty,
@@ -288,7 +288,7 @@ fn identify_bad_closure_def_and_call(
         callee_span: Span,
     ) {
         let hir = self.tcx.hir();
-        let parent_hir_id = hir.get_parent_node(hir_id);
+        let parent_hir_id = hir.parent_id(hir_id);
         let parent_node = hir.get(parent_hir_id);
         if let (
             hir::Node::Expr(hir::Expr {
@@ -303,7 +303,7 @@ fn identify_bad_closure_def_and_call(
             {
                 // Actually need to unwrap a few more layers of HIR to get to
                 // the _real_ closure...
-                let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
+                let async_closure = hir.parent_id(hir.parent_id(parent_hir_id));
                 if let hir::Node::Expr(hir::Expr {
                     kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                     ..
@@ -336,7 +336,7 @@ fn maybe_suggest_bad_array_definition(
         call_expr: &'tcx hir::Expr<'tcx>,
         callee_expr: &'tcx hir::Expr<'tcx>,
     ) -> bool {
-        let hir_id = self.tcx.hir().get_parent_node(call_expr.hir_id);
+        let hir_id = self.tcx.hir().parent_id(call_expr.hir_id);
         let parent_node = self.tcx.hir().get(hir_id);
         if let (
             hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
index 5bd02dff73bfc1f033318eff0d0568c9e382d9cb..399702fd41abcdabbeb055e5629452d6ddc3f0e8 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitor};
 use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
@@ -21,6 +21,7 @@
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use std::cmp;
 use std::iter;
+use std::ops::ControlFlow;
 
 /// What signature do we *expect* the closure to have from context?
 #[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
@@ -54,7 +55,7 @@ pub fn check_expr_closure(
         // closure sooner rather than later, so first examine the expected
         // type, and see if can glean a closure kind from there.
         let (expected_sig, expected_kind) = match expected.to_option(self) {
-            Some(ty) => self.deduce_expectations_from_expected_type(ty),
+            Some(ty) => self.deduce_closure_signature(ty),
             None => (None, None),
         };
         let body = self.tcx.hir().body(closure.body);
@@ -162,13 +163,14 @@ fn check_closure(
     /// Given the expected type, figures out what it can about this closure we
     /// are about to type check:
     #[instrument(skip(self), level = "debug")]
-    fn deduce_expectations_from_expected_type(
+    fn deduce_closure_signature(
         &self,
         expected_ty: Ty<'tcx>,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         match *expected_ty.kind() {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
-                .deduce_signature_from_predicates(
+                .deduce_closure_signature_from_predicates(
+                    expected_ty,
                     self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
                 ),
             ty::Dynamic(ref object_type, ..) => {
@@ -181,7 +183,8 @@ fn deduce_expectations_from_expected_type(
                     .and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
                 (sig, kind)
             }
-            ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates(
+            ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
+                self.tcx.mk_ty_var(self.root_var(vid)),
                 self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
             ),
             ty::FnPtr(sig) => {
@@ -192,8 +195,9 @@ fn deduce_expectations_from_expected_type(
         }
     }
 
-    fn deduce_signature_from_predicates(
+    fn deduce_closure_signature_from_predicates(
         &self,
+        expected_ty: Ty<'tcx>,
         predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         let mut expected_sig = None;
@@ -214,13 +218,33 @@ fn deduce_signature_from_predicates(
             if expected_sig.is_none()
                 && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder()
             {
-                expected_sig = self.normalize(
+                let inferred_sig = self.normalize(
                     obligation.cause.span,
                     self.deduce_sig_from_projection(
                     Some(obligation.cause.span),
                         bound_predicate.rebind(proj_predicate),
                     ),
                 );
+                // Make sure that we didn't infer a signature that mentions itself.
+                // This can happen when we elaborate certain supertrait bounds that
+                // mention projections containing the `Self` type. See #105401.
+                struct MentionsTy<'tcx> {
+                    expected_ty: Ty<'tcx>,
+                }
+                impl<'tcx> TypeVisitor<'tcx> for MentionsTy<'tcx> {
+                    type BreakTy = ();
+
+                    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+                        if t == self.expected_ty {
+                            ControlFlow::BREAK
+                        } else {
+                            t.super_visit_with(self)
+                        }
+                    }
+                }
+                if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
+                    expected_sig = inferred_sig;
+                }
             }
 
             // Even if we can't infer the full signature, we may be able to
@@ -623,14 +647,12 @@ fn supplied_sig_of_closure(
             ),
             bound_vars,
         );
-        // Astconv can't normalize inputs or outputs with escaping bound vars,
-        // so normalize them here, after we've wrapped them in a binder.
-        let result = self.normalize(self.tcx.hir().span(hir_id), result);
 
         let c_result = self.inh.infcx.canonicalize_response(result);
         self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
 
-        result
+        // Normalize only after registering in `user_provided_sigs`.
+        self.normalize(self.tcx.hir().span(hir_id), result)
     }
 
     /// Invoked when we are translating the generator that results
index b0cd4a16e9869270546b1a485cb0479ddd7b7626..9e91a3f90764cf4c879d0f2f3b6043052baa0f10 100644 (file)
@@ -171,6 +171,10 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
 
         // Just ignore error types.
         if a.references_error() || b.references_error() {
+            // Best-effort try to unify these types -- we're already on the error path,
+            // so this will have the side-effect of making sure we have no ambiguities
+            // due to `[type error]` and `_` not coercing together.
+            let _ = self.commit_if_ok(|_| self.at(&self.cause, self.param_env).eq(a, b));
             return success(vec![], self.fcx.tcx.ty_error(), vec![]);
         }
 
@@ -1543,7 +1547,7 @@ pub(crate) fn coerce_inner<'a>(
                         err.span_label(cause.span, "return type is not `()`");
                     }
                     ObligationCauseCode::BlockTailExpression(blk_id) => {
-                        let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
+                        let parent_id = fcx.tcx.hir().parent_id(blk_id);
                         err = self.report_return_mismatched_types(
                             cause,
                             expected,
@@ -1574,7 +1578,7 @@ pub(crate) fn coerce_inner<'a>(
                             None,
                         );
                         if !fcx.tcx.features().unsized_locals {
-                            let id = fcx.tcx.hir().get_parent_node(id);
+                            let id = fcx.tcx.hir().parent_id(id);
                             unsized_return = self.is_return_ty_unsized(fcx, id);
                         }
                     }
@@ -1664,7 +1668,7 @@ fn report_return_mismatched_types<'a>(
         let mut pointing_at_return_type = false;
         let mut fn_output = None;
 
-        let parent_id = fcx.tcx.hir().get_parent_node(id);
+        let parent_id = fcx.tcx.hir().parent_id(id);
         let parent = fcx.tcx.hir().get(parent_id);
         if let Some(expr) = expression
             && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent
index 042ff0b46a5afbc6bd31205d2600a732d9c002c0..f68a428d09ae3ba4b1d7f4e5043d7c0b71bc064c 100644 (file)
@@ -1,8 +1,11 @@
 use crate::FnCtxt;
 use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::MultiSpan;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
 use rustc_infer::infer::InferOk;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
+use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
+use rustc_middle::ty::relate::TypeRelation;
+use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeVisitable};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::method_chain::CollectAllMismatches;
 use rustc_trait_selection::traits::ObligationCause;
 
 use super::method::probe;
@@ -30,14 +36,16 @@ pub fn emit_type_mismatch_suggestions(
         expr_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
-        _error: Option<TypeError<'tcx>>,
+        error: Option<TypeError<'tcx>>,
     ) {
         if expr_ty == expected {
             return;
         }
 
+        self.annotate_alternative_method_deref(err, expr, error);
+
         // Use `||` to give these suggestions a precedence
-        let _ = self.suggest_missing_parentheses(err, expr)
+        let suggested = self.suggest_missing_parentheses(err, expr)
             || self.suggest_remove_last_method_call(err, expr, expected)
             || self.suggest_associated_const(err, expr, expected)
             || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
@@ -49,8 +57,12 @@ pub fn emit_type_mismatch_suggestions(
             || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
             || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
             || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+            || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
             || self.suggest_into(err, expr, expr_ty, expected)
             || self.suggest_floating_point_literal(err, expr, expected);
+        if !suggested {
+            self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected);
+        }
     }
 
     pub fn emit_coerce_suggestions(
@@ -71,6 +83,8 @@ pub fn emit_coerce_suggestions(
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
+        self.check_for_range_as_method_call(err, expr, expr_ty, expected);
+        self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
     }
 
     /// Requires that the two types unify, and prints an error message if
@@ -201,13 +215,222 @@ pub fn demand_coerce_diag(
         (expected, Some(err))
     }
 
+    pub fn point_at_expr_source_of_inferred_type(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        found: Ty<'tcx>,
+        expected: Ty<'tcx>,
+    ) -> bool {
+        let map = self.tcx.hir();
+
+        let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; };
+        let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; };
+        let hir::def::Res::Local(hir_id) = p.res else { return false; };
+        let Some(hir::Node::Pat(pat)) = map.find(hir_id) else { return false; };
+        let Some(hir::Node::Local(hir::Local {
+            ty: None,
+            init: Some(init),
+            ..
+        })) = map.find_parent(pat.hir_id) else { return false; };
+        let Some(ty) = self.node_ty_opt(init.hir_id) else { return false; };
+        if ty.is_closure() || init.span.overlaps(expr.span) || pat.span.from_expansion() {
+            return false;
+        }
+
+        // Locate all the usages of the relevant binding.
+        struct FindExprs<'hir> {
+            hir_id: hir::HirId,
+            uses: Vec<&'hir hir::Expr<'hir>>,
+        }
+        impl<'v> Visitor<'v> for FindExprs<'v> {
+            fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+                if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
+                    && let hir::def::Res::Local(hir_id) = path.res
+                    && hir_id == self.hir_id
+                {
+                    self.uses.push(ex);
+                }
+                hir::intravisit::walk_expr(self, ex);
+            }
+        }
+
+        let mut expr_finder = FindExprs { hir_id, uses: vec![] };
+        let id = map.get_parent_item(hir_id);
+        let hir_id: hir::HirId = id.into();
+
+        let Some(node) = map.find(hir_id) else { return false; };
+        let Some(body_id) = node.body_id() else { return false; };
+        let body = map.body(body_id);
+        expr_finder.visit_expr(body.value);
+        // Hack to make equality checks on types with inference variables and regions useful.
+        let mut eraser = BottomUpFolder {
+            tcx: self.tcx,
+            lt_op: |_| self.tcx.lifetimes.re_erased,
+            ct_op: |c| c,
+            ty_op: |t| match *t.kind() {
+                ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))),
+                ty::Infer(ty::IntVar(_)) => {
+                    self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 }))
+                }
+                ty::Infer(ty::FloatVar(_)) => {
+                    self.tcx.mk_ty_infer(ty::FloatVar(ty::FloatVid { index: 0 }))
+                }
+                _ => t,
+            },
+        };
+        let mut prev = eraser.fold_ty(ty);
+        let mut prev_span = None;
+
+        for binding in expr_finder.uses {
+            // In every expression where the binding is referenced, we will look at that
+            // expression's type and see if it is where the incorrect found type was fully
+            // "materialized" and point at it. We will also try to provide a suggestion there.
+            if let Some(hir::Node::Expr(expr)
+            | hir::Node::Stmt(hir::Stmt {
+                kind: hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr),
+                ..
+            })) = &map.find_parent(binding.hir_id)
+                && let hir::ExprKind::MethodCall(segment, rcvr, args, _span) = expr.kind
+                && rcvr.hir_id == binding.hir_id
+                && let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
+            {
+                // We special case methods, because they can influence inference through the
+                // call's arguments and we can provide a more explicit span.
+                let sig = self.tcx.fn_sig(def_id);
+                let def_self_ty = sig.input(0).skip_binder();
+                let rcvr_ty = self.node_ty(rcvr.hir_id);
+                // Get the evaluated type *after* calling the method call, so that the influence
+                // of the arguments can be reflected in the receiver type. The receiver
+                // expression has the type *before* theis analysis is done.
+                let ty = match self.lookup_probe(
+                    segment.ident,
+                    rcvr_ty,
+                    expr,
+                    probe::ProbeScope::TraitsInScope,
+                ) {
+                    Ok(pick) => pick.self_ty,
+                    Err(_) => rcvr_ty,
+                };
+                // Remove one layer of references to account for `&mut self` and
+                // `&self`, so that we can compare it against the binding.
+                let (ty, def_self_ty) = match (ty.kind(), def_self_ty.kind()) {
+                    (ty::Ref(_, ty, a), ty::Ref(_, self_ty, b)) if a == b => (*ty, *self_ty),
+                    _ => (ty, def_self_ty),
+                };
+                let mut param_args = FxHashMap::default();
+                let mut param_expected = FxHashMap::default();
+                let mut param_found = FxHashMap::default();
+                if self.can_eq(self.param_env, ty, found).is_ok() {
+                    // We only point at the first place where the found type was inferred.
+                    for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() {
+                        if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() {
+                            // We found an argument that references a type parameter in `Self`,
+                            // so we assume that this is the argument that caused the found
+                            // type, which we know already because of `can_eq` above was first
+                            // inferred in this method call.
+                            let arg = &args[i];
+                            let arg_ty = self.node_ty(arg.hir_id);
+                            err.span_label(
+                                arg.span,
+                                &format!(
+                                    "this is of type `{arg_ty}`, which causes `{ident}` to be \
+                                     inferred as `{ty}`",
+                                ),
+                            );
+                            param_args.insert(param_ty, (arg, arg_ty));
+                        }
+                    }
+                }
+
+                // Here we find, for a type param `T`, the type that `T` is in the current
+                // method call *and* in the original expected type. That way, we can see if we
+                // can give any structured suggestion for the function argument.
+                let mut c = CollectAllMismatches {
+                    infcx: &self.infcx,
+                    param_env: self.param_env,
+                    errors: vec![],
+                };
+                let _ = c.relate(def_self_ty, ty);
+                for error in c.errors {
+                    if let TypeError::Sorts(error) = error {
+                        param_found.insert(error.expected, error.found);
+                    }
+                }
+                c.errors = vec![];
+                let _ = c.relate(def_self_ty, expected);
+                for error in c.errors {
+                    if let TypeError::Sorts(error) = error {
+                        param_expected.insert(error.expected, error.found);
+                    }
+                }
+                for (param, (arg, arg_ty)) in param_args.iter() {
+                    let Some(expected) = param_expected.get(param) else { continue; };
+                    let Some(found) = param_found.get(param) else { continue; };
+                    if self.can_eq(self.param_env, *arg_ty, *found).is_err() { continue; }
+                    self.emit_coerce_suggestions(err, arg, *found, *expected, None, None);
+                }
+
+                let ty = eraser.fold_ty(ty);
+                if ty.references_error() {
+                    break;
+                }
+                if ty != prev
+                    && param_args.is_empty()
+                    && self.can_eq(self.param_env, ty, found).is_ok()
+                {
+                    // We only point at the first place where the found type was inferred.
+                    err.span_label(
+                        segment.ident.span,
+                        with_forced_trimmed_paths!(format!(
+                            "here the type of `{ident}` is inferred to be `{ty}`",
+                        )),
+                    );
+                    break;
+                } else if !param_args.is_empty() {
+                    break;
+                }
+                prev = ty;
+            } else {
+                let ty = eraser.fold_ty(self.node_ty(binding.hir_id));
+                if ty.references_error() {
+                    break;
+                }
+                if ty != prev
+                    && let Some(span) = prev_span
+                    && self.can_eq(self.param_env, ty, found).is_ok()
+                {
+                    // We only point at the first place where the found type was inferred.
+                    // We use the *previous* span because if the type is known *here* it means
+                    // it was *evaluated earlier*. We don't do this for method calls because we
+                    // evaluate the method's self type eagerly, but not in any other case.
+                    err.span_label(
+                        span,
+                        with_forced_trimmed_paths!(format!(
+                            "here the type of `{ident}` is inferred to be `{ty}`",
+                        )),
+                    );
+                    break;
+                }
+                prev = ty;
+            }
+            if binding.hir_id == expr.hir_id {
+                // Do not look at expressions that come after the expression we were originally
+                // evaluating and had a type error.
+                break;
+            }
+            prev_span = Some(binding.span);
+        }
+        true
+    }
+
     fn annotate_expected_due_to_let_ty(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
         error: Option<TypeError<'tcx>>,
     ) {
-        let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+        let parent = self.tcx.hir().parent_id(expr.hir_id);
         match (self.tcx.hir().find(parent), error) {
             (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
                 if init.hir_id == expr.hir_id =>
@@ -254,10 +477,9 @@ fn annotate_expected_due_to_let_ty(
                         hir::Path { res: hir::def::Res::Local(hir_id), .. },
                     )) => {
                         if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) {
-                            let parent = self.tcx.hir().get_parent_node(pat.hir_id);
                             primary_span = pat.span;
                             secondary_span = pat.span;
-                            match self.tcx.hir().find(parent) {
+                            match self.tcx.hir().find_parent(pat.hir_id) {
                                 Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
                                     primary_span = ty.span;
                                     post_message = " type";
@@ -316,6 +538,162 @@ fn annotate_expected_due_to_let_ty(
         }
     }
 
+    fn annotate_alternative_method_deref(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        error: Option<TypeError<'tcx>>,
+    ) {
+        let parent = self.tcx.hir().parent_id(expr.hir_id);
+        let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;};
+        let Some(hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Assign(lhs, rhs, _), ..
+                })) = self.tcx.hir().find(parent) else {return; };
+        if rhs.hir_id != expr.hir_id || expected.is_closure() {
+            return;
+        }
+        let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; };
+        let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; };
+        let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; };
+
+        let Ok(pick) = self
+            .probe_for_name(
+                probe::Mode::MethodCall,
+                path.ident,
+                probe::IsSuggestion(true),
+                self_ty,
+                deref.hir_id,
+                probe::ProbeScope::TraitsInScope,
+            ) else {
+                return;
+            };
+        let in_scope_methods = self.probe_for_name_many(
+            probe::Mode::MethodCall,
+            path.ident,
+            probe::IsSuggestion(true),
+            self_ty,
+            deref.hir_id,
+            probe::ProbeScope::TraitsInScope,
+        );
+        let other_methods_in_scope: Vec<_> =
+            in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
+
+        let all_methods = self.probe_for_name_many(
+            probe::Mode::MethodCall,
+            path.ident,
+            probe::IsSuggestion(true),
+            self_ty,
+            deref.hir_id,
+            probe::ProbeScope::AllTraits,
+        );
+        let suggestions: Vec<_> = all_methods
+            .into_iter()
+            .filter(|c| c.item.def_id != pick.item.def_id)
+            .map(|c| {
+                let m = c.item;
+                let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
+                    self.var_for_def(deref.span, param)
+                });
+                vec![
+                    (
+                        deref.span.until(base.span),
+                        format!(
+                            "{}({}",
+                            with_no_trimmed_paths!(
+                                self.tcx.def_path_str_with_substs(m.def_id, substs,)
+                            ),
+                            match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() {
+                                ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
+                                ty::Ref(_, _, _) => "&",
+                                _ => "",
+                            },
+                        ),
+                    ),
+                    match &args[..] {
+                        [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
+                        [first, ..] => (base.span.between(first.span), ", ".to_string()),
+                    },
+                ]
+            })
+            .collect();
+        if suggestions.is_empty() {
+            return;
+        }
+        let mut path_span: MultiSpan = path.ident.span.into();
+        path_span.push_span_label(
+            path.ident.span,
+            with_no_trimmed_paths!(format!(
+                "refers to `{}`",
+                self.tcx.def_path_str(pick.item.def_id),
+            )),
+        );
+        let container_id = pick.item.container_id(self.tcx);
+        let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
+        for def_id in pick.import_ids {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+            path_span.push_span_label(
+                self.tcx.hir().span(hir_id),
+                format!("`{container}` imported here"),
+            );
+        }
+        let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] {
+            [] => return,
+            [candidate] => format!(
+                "the method of the same name on {} `{}`",
+                match candidate.kind {
+                    probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
+                    _ => "trait",
+                },
+                self.tcx.def_path_str(candidate.item.container_id(self.tcx))
+            ),
+            [.., last] if other_methods_in_scope.len() < 5 => {
+                format!(
+                    "the methods of the same name on {} and `{}`",
+                    other_methods_in_scope[..other_methods_in_scope.len() - 1]
+                        .iter()
+                        .map(|c| format!(
+                            "`{}`",
+                            self.tcx.def_path_str(c.item.container_id(self.tcx))
+                        ))
+                        .collect::<Vec<String>>()
+                        .join(", "),
+                    self.tcx.def_path_str(last.item.container_id(self.tcx))
+                )
+            }
+            _ => format!(
+                "the methods of the same name on {} other traits",
+                other_methods_in_scope.len()
+            ),
+        });
+        err.span_note(
+            path_span,
+            &format!(
+                "the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
+                path.ident,
+            ),
+        );
+        if suggestions.len() > other_methods_in_scope.len() {
+            err.note(&format!(
+                "additionally, there are {} other available methods that aren't in scope",
+                suggestions.len() - other_methods_in_scope.len()
+            ));
+        }
+        err.multipart_suggestions(
+            &format!(
+                "you might have meant to call {}; you can use the fully-qualified path to call {} \
+                 explicitly",
+                if suggestions.len() == 1 {
+                    "the other method"
+                } else {
+                    "one of the other methods"
+                },
+                if suggestions.len() == 1 { "it" } else { "one of them" },
+            ),
+            suggestions,
+            Applicability::MaybeIncorrect,
+        );
+    }
+
     /// If the expected type is an enum (Issue #55250) with any variants whose
     /// sole field is of the found type, suggest such variants. (Issue #42764)
     fn suggest_compatible_variants(
@@ -350,7 +728,7 @@ fn suggest_compatible_variants(
 
                 // Unroll desugaring, to make sure this works for `for` loops etc.
                 loop {
-                    parent = self.tcx.hir().get_parent_node(id);
+                    parent = self.tcx.hir().parent_id(id);
                     if let Some(parent_span) = self.tcx.hir().opt_span(parent) {
                         if parent_span.find_ancestor_inside(expr.span).is_some() {
                             // The parent node is part of the same span, so is the result of the
@@ -630,12 +1008,12 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
             return None;
         };
 
-        let local_parent = self.tcx.hir().get_parent_node(local_id);
+        let local_parent = self.tcx.hir().parent_id(local_id);
         let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = self.tcx.hir().find(local_parent) else {
             return None;
         };
 
-        let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
+        let param_parent = self.tcx.hir().parent_id(*param_hir_id);
         let Some(Node::Expr(hir::Expr {
             hir_id: expr_hir_id,
             kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
@@ -644,7 +1022,7 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
             return None;
         };
 
-        let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id);
+        let expr_parent = self.tcx.hir().parent_id(*expr_hir_id);
         let hir = self.tcx.hir().find(expr_parent);
         let closure_params_len = closure_fn_decl.inputs.len();
         let (
@@ -697,7 +1075,7 @@ pub(crate) fn maybe_get_struct_pattern_shorthand_field(
             _ => None,
         }?;
 
-        match hir.find(hir.get_parent_node(expr.hir_id))? {
+        match hir.find_parent(expr.hir_id)? {
             Node::ExprField(field) => {
                 if field.ident.name == local.name && field.is_shorthand {
                     return Some(local.name);
@@ -723,7 +1101,7 @@ pub(crate) fn maybe_get_block_expr(
     /// Returns whether the given expression is an `else if`.
     pub(crate) fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
         if let hir::ExprKind::If(..) = expr.kind {
-            let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
+            let parent_id = self.tcx.hir().parent_id(expr.hir_id);
             if let Some(Node::Expr(hir::Expr {
                 kind: hir::ExprKind::If(_, _, Some(else_expr)),
                 ..
@@ -880,7 +1258,7 @@ pub fn check_ref(
                         if let Some(hir::Node::Expr(hir::Expr {
                             kind: hir::ExprKind::Assign(..),
                             ..
-                        })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
+                        })) = self.tcx.hir().find_parent(expr.hir_id)
                         {
                             if mutability.is_mut() {
                                 // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
@@ -1002,7 +1380,7 @@ pub fn check_ref(
                         }
                     }
                     // If we've reached our target type with just removing `&`, then just print now.
-                    if steps == 0 {
+                    if steps == 0 && !remove.trim().is_empty() {
                         return Some((
                             prefix_span,
                             format!("consider removing the `{}`", remove.trim()),
@@ -1061,6 +1439,9 @@ pub fn check_ref(
                         } else {
                             (prefix_span, format!("{}{}", prefix, "*".repeat(steps)))
                         };
+                        if suggestion.trim().is_empty() {
+                            return None;
+                        }
 
                         return Some((
                             span,
@@ -1107,9 +1488,7 @@ pub fn check_for_cast(
 
         let mut sugg = vec![];
 
-        if let Some(hir::Node::ExprField(field)) =
-            self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
-        {
+        if let Some(hir::Node::ExprField(field)) = self.tcx.hir().find_parent(expr.hir_id) {
             // `expr` is a literal field for a struct, only suggest if appropriate
             if field.is_shorthand {
                 // This is a field literal
@@ -1448,4 +1827,113 @@ pub fn check_for_cast(
             _ => false,
         }
     }
+
+    /// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
+    pub fn check_for_range_as_method_call(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        checked_ty: Ty<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) {
+        if !hir::is_range_literal(expr) {
+            return;
+        }
+        let hir::ExprKind::Struct(
+            hir::QPath::LangItem(LangItem::Range, ..),
+            [start, end],
+            _,
+        ) = expr.kind else { return; };
+        let parent = self.tcx.hir().parent_id(expr.hir_id);
+        if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) {
+            // Ignore `Foo { field: a..Default::default() }`
+            return;
+        }
+        let mut expr = end.expr;
+        while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind {
+            // Getting to the root receiver and asserting it is a fn call let's us ignore cases in
+            // `src/test/ui/methods/issues/issue-90315.stderr`.
+            expr = rcvr;
+        }
+        let hir::ExprKind::Call(method_name, _) = expr.kind else { return; };
+        let ty::Adt(adt, _) = checked_ty.kind() else { return; };
+        if self.tcx.lang_items().range_struct() != Some(adt.did()) {
+            return;
+        }
+        if let ty::Adt(adt, _) = expected_ty.kind()
+            && self.tcx.lang_items().range_struct() == Some(adt.did())
+        {
+            return;
+        }
+        // Check if start has method named end.
+        let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; };
+        let [hir::PathSegment { ident, .. }] = p.segments else { return; };
+        let self_ty = self.typeck_results.borrow().expr_ty(start.expr);
+        let Ok(_pick) = self.probe_for_name(
+            probe::Mode::MethodCall,
+            *ident,
+            probe::IsSuggestion(true),
+            self_ty,
+            expr.hir_id,
+            probe::ProbeScope::AllTraits,
+        ) else { return; };
+        let mut sugg = ".";
+        let mut span = start.expr.span.between(end.expr.span);
+        if span.lo() + BytePos(2) == span.hi() {
+            // There's no space between the start, the range op and the end, suggest removal which
+            // will be more noticeable than the replacement of `..` with `.`.
+            span = span.with_lo(span.lo() + BytePos(1));
+            sugg = "";
+        }
+        err.span_suggestion_verbose(
+            span,
+            "you likely meant to write a method call instead of a range",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    }
+
+    /// Identify when the type error is because `()` is found in a binding that was assigned a
+    /// block without a tail expression.
+    fn check_for_binding_assigned_block_without_tail_expression(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        checked_ty: Ty<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) {
+        if !checked_ty.is_unit() {
+            return;
+        }
+        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
+        let hir::def::Res::Local(hir_id) = path.res else { return; };
+        let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
+            return;
+        };
+        let Some(hir::Node::Local(hir::Local {
+            ty: None,
+            init: Some(init),
+            ..
+        })) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
+        let hir::ExprKind::Block(block, None) = init.kind else { return; };
+        if block.expr.is_some() {
+            return;
+        }
+        let [.., stmt] = block.stmts else {
+            err.span_label(block.span, "this empty block is missing a tail expression");
+            return;
+        };
+        let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
+        let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; };
+        if self.can_eq(self.param_env, expected_ty, ty).is_ok() {
+            err.span_suggestion_short(
+                stmt.span.with_lo(tail_expr.span.hi()),
+                "remove this semicolon",
+                "",
+                Applicability::MachineApplicable,
+            );
+        } else {
+            err.span_label(block.span, "this block is missing a tail expression");
+        }
+    }
 }
index ae641b26eeedbb48898bb1019e747c217b57833a..b08b22108c8ce899ac43859a95caf83919bbec6b 100644 (file)
@@ -234,6 +234,7 @@ pub(super) fn check_expr_with_expectation_and_args(
             ) => self.check_expr_path(qpath, expr, args),
             _ => self.check_expr_kind(expr, expected),
         });
+        let ty = self.resolve_vars_if_possible(ty);
 
         // Warn for non-block expressions with diverging children.
         match expr.kind {
@@ -395,7 +396,7 @@ fn check_expr_unary(
                             E0614,
                             "type `{oprnd_t}` cannot be dereferenced",
                         );
-                        let sp = tcx.sess.source_map().start_point(expr.span);
+                        let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None);
                         if let Some(sp) =
                             tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
                         {
@@ -920,7 +921,7 @@ pub(super) fn comes_from_while_condition(
         original_expr_id: HirId,
         then: impl FnOnce(&hir::Expr<'_>),
     ) {
-        let mut parent = self.tcx.hir().get_parent_node(original_expr_id);
+        let mut parent = self.tcx.hir().parent_id(original_expr_id);
         while let Some(node) = self.tcx.hir().find(parent) {
             match node {
                 hir::Node::Expr(hir::Expr {
@@ -943,7 +944,7 @@ pub(super) fn comes_from_while_condition(
                 }) => {
                     // Check if our original expression is a child of the condition of a while loop
                     let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| {
-                        self.tcx.hir().find_parent_node(*id)
+                        self.tcx.hir().opt_parent_id(*id)
                     })
                     .take_while(|id| *id != parent)
                     .any(|id| id == expr.hir_id);
@@ -959,7 +960,7 @@ pub(super) fn comes_from_while_condition(
                 | hir::Node::TraitItem(_)
                 | hir::Node::Crate(_) => break,
                 _ => {
-                    parent = self.tcx.hir().get_parent_node(parent);
+                    parent = self.tcx.hir().parent_id(parent);
                 }
             }
         }
@@ -1083,7 +1084,7 @@ fn check_expr_assign(
                 // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
                 let hir = self.tcx.hir();
                 if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
-                    hir.get(hir.get_parent_node(hir.get_parent_node(expr.hir_id)))
+                    hir.get_parent(hir.parent_id(expr.hir_id))
                 {
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_lo(),
@@ -2216,7 +2217,7 @@ fn check_field(
                             self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
                             return field_ty;
                         }
-                        private_candidate = Some((adjustments, base_def.did(), field_ty));
+                        private_candidate = Some((adjustments, base_def.did()));
                     }
                 }
                 ty::Tuple(tys) => {
@@ -2239,12 +2240,12 @@ fn check_field(
         }
         self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
-        if let Some((adjustments, did, field_ty)) = private_candidate {
+        if let Some((adjustments, did)) = private_candidate {
             // (#90483) apply adjustments to avoid ExprUseVisitor from
             // creating erroneous projection.
             self.apply_adjustments(base, adjustments);
             self.ban_private_field_access(expr, base_ty, field, did);
-            return field_ty;
+            return self.tcx().ty_error();
         }
 
         if field.name == kw::Empty {
@@ -2462,7 +2463,7 @@ fn ban_take_value_of_method(&self, expr: &hir::Expr<'_>, expr_t: Ty<'tcx>, field
         err.span_label(field.span, "method, not a field");
         let expr_is_call =
             if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) =
-                self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id))
+                self.tcx.hir().get_parent(expr.hir_id)
             {
                 expr.hir_id == callee.hir_id
             } else {
index 150e917c73988bef7126b16ede746d8a60b20eec..b7681d108ed01febb082121e5589dec25f117770 100644 (file)
@@ -1,7 +1,7 @@
 use crate::callee::{self, DeferredCallResolution};
 use crate::method::{self, MethodCallee, SelfSource};
 use crate::rvalue_scopes;
-use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@@ -24,7 +24,7 @@
 use rustc_middle::ty::{
     self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, UserType,
 };
-use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
+use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
@@ -161,47 +161,6 @@ pub(in super::super) fn write_resolution(
     pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
         self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
         self.write_substs(hir_id, method.substs);
-
-        // When the method is confirmed, the `method.substs` includes
-        // parameters from not just the method, but also the impl of
-        // the method -- in particular, the `Self` type will be fully
-        // resolved. However, those are not something that the "user
-        // specified" -- i.e., those types come from the inferred type
-        // of the receiver, not something the user wrote. So when we
-        // create the user-substs, we want to replace those earlier
-        // types with just the types that the user actually wrote --
-        // that is, those that appear on the *method itself*.
-        //
-        // As an example, if the user wrote something like
-        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
-        // type of `foo` (possibly adjusted), but we don't want to
-        // include that. We want just the `[_, u32]` part.
-        if !method.substs.is_empty() {
-            let method_generics = self.tcx.generics_of(method.def_id);
-            if !method_generics.params.is_empty() {
-                let user_type_annotation = self.probe(|_| {
-                    let user_substs = UserSubsts {
-                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
-                            let i = param.index as usize;
-                            if i < method_generics.parent_count {
-                                self.var_for_def(DUMMY_SP, param)
-                            } else {
-                                method.substs[i]
-                            }
-                        }),
-                        user_self_ty: None, // not relevant here
-                    };
-
-                    self.canonicalize_user_type_annotation(UserType::TypeOf(
-                        method.def_id,
-                        user_substs,
-                    ))
-                });
-
-                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
-                self.write_user_type_annotation(hir_id, user_type_annotation);
-            }
-        }
     }
 
     pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
@@ -410,23 +369,38 @@ pub fn register_bound(
         }
     }
 
-    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
+    pub fn handle_raw_ty(&self, span: Span, ty: Ty<'tcx>) -> RawTy<'tcx> {
+        RawTy { raw: ty, normalized: self.normalize(span, ty) }
+    }
+
+    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> RawTy<'tcx> {
         let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t);
         self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
-        t
+        self.handle_raw_ty(ast_t.span, t)
     }
 
     pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         let ty = self.to_ty(ast_ty);
         debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
 
-        if Self::can_contain_user_lifetime_bounds(ty) {
-            let c_ty = self.canonicalize_response(UserType::Ty(ty));
+        if Self::can_contain_user_lifetime_bounds(ty.raw) {
+            let c_ty = self.canonicalize_response(UserType::Ty(ty.raw));
             debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
             self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
         }
 
-        ty
+        ty.normalized
+    }
+
+    pub(super) fn user_substs_for_adt(ty: RawTy<'tcx>) -> UserSubsts<'tcx> {
+        match (ty.raw.kind(), ty.normalized.kind()) {
+            (ty::Adt(_, substs), _) => UserSubsts { substs, user_self_ty: None },
+            (_, ty::Adt(adt, substs)) => UserSubsts {
+                substs,
+                user_self_ty: Some(UserSelfTy { impl_def_id: adt.did(), self_ty: ty.raw }),
+            },
+            _ => bug!("non-adt type {:?}", ty),
+        }
     }
 
     pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
@@ -780,7 +754,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
         qpath: &'tcx QPath<'tcx>,
         hir_id: hir::HirId,
         span: Span,
-    ) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
+    ) -> (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
         debug!(
             "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
             qpath, hir_id, span
@@ -803,7 +777,8 @@ pub fn resolve_ty_and_res_fully_qualified_call(
                 // to be object-safe.
                 // We manually call `register_wf_obligation` in the success path
                 // below.
-                (<dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself), qself, segment)
+                let ty = <dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself);
+                (self.handle_raw_ty(span, ty), qself, segment)
             }
             QPath::LangItem(..) => {
                 bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
@@ -811,7 +786,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
         };
         if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
         {
-            self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+            self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None));
             // Return directly on cache hit. This is useful to avoid doubly reporting
             // errors with default match binding modes. See #44614.
             let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
@@ -819,7 +794,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
         }
         let item_name = item_segment.ident;
         let result = self
-            .resolve_fully_qualified_call(span, item_name, ty, qself.span, hir_id)
+            .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
             .or_else(|error| {
                 let result = match error {
                     method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
@@ -830,13 +805,17 @@ pub fn resolve_ty_and_res_fully_qualified_call(
                 // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
                 // register a WF obligation so that we can detect any additional
                 // errors in the self type.
-                if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) {
-                    self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+                if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) {
+                    self.register_wf_obligation(
+                        ty.raw.into(),
+                        qself.span,
+                        traits::WellFormed(None),
+                    );
                 }
                 if item_name.name != kw::Empty {
                     if let Some(mut e) = self.report_method_error(
                         span,
-                        ty,
+                        ty.normalized,
                         item_name,
                         SelfSource::QPath(qself),
                         error,
@@ -849,7 +828,7 @@ pub fn resolve_ty_and_res_fully_qualified_call(
             });
 
         if result.is_ok() {
-            self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+            self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None));
         }
 
         // Write back the new resolution.
@@ -986,7 +965,7 @@ pub(in super::super) fn note_need_for_fn_pointer(
     pub fn instantiate_value_path(
         &self,
         segments: &[hir::PathSegment<'_>],
-        self_ty: Option<Ty<'tcx>>,
+        self_ty: Option<RawTy<'tcx>>,
         res: Res,
         span: Span,
         hir_id: hir::HirId,
@@ -996,7 +975,12 @@ pub fn instantiate_value_path(
         let path_segs = match res {
             Res::Local(_) | Res::SelfCtor(_) => vec![],
             Res::Def(kind, def_id) => <dyn AstConv<'_>>::def_ids_for_value_path_segments(
-                self, segments, self_ty, kind, def_id,
+                self,
+                segments,
+                self_ty.map(|ty| ty.raw),
+                kind,
+                def_id,
+                span,
             ),
             _ => bug!("instantiate_value_path on {:?}", res),
         };
@@ -1007,8 +991,8 @@ pub fn instantiate_value_path(
             Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
                 if let Some(self_ty) = self_ty =>
             {
-                let adt_def = self_ty.ty_adt_def().unwrap();
-                user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty });
+                let adt_def = self_ty.normalized.ty_adt_def().unwrap();
+                user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw });
                 is_alias_variant_ctor = true;
             }
             Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
@@ -1027,7 +1011,7 @@ pub fn instantiate_value_path(
                             // inherent impl, we need to record the
                             // `T` for posterity (see `UserSelfTy` for
                             // details).
-                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self").raw;
                             user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
                         }
                     }
@@ -1109,19 +1093,21 @@ pub fn instantiate_value_path(
             .unwrap_or(false);
 
         let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
-            match *ty.kind() {
-                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
-                    let variant = adt_def.non_enum_variant();
-                    let (ctor_kind, ctor_def_id) = variant.ctor.unwrap();
-                    (Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id), Some(substs))
+            let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id));
+            match ty.normalized.ty_adt_def() {
+                Some(adt_def) if adt_def.has_ctor() => {
+                    let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
+                    let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
+                    let user_substs = Self::user_substs_for_adt(ty);
+                    user_self_ty = user_substs.user_self_ty;
+                    (new_res, Some(user_substs.substs))
                 }
                 _ => {
                     let mut err = tcx.sess.struct_span_err(
                         span,
                         "the `Self` constructor can only be used with tuple or unit structs",
                     );
-                    if let Some(adt_def) = ty.ty_adt_def() {
+                    if let Some(adt_def) = ty.normalized.ty_adt_def() {
                         match adt_def.adt_kind() {
                             AdtKind::Enum => {
                                 err.help("did you mean to use one of the enum's variants?");
@@ -1193,7 +1179,7 @@ fn provided_kind(
                         <dyn AstConv<'_>>::ast_region_to_region(self.fcx, lt, Some(param)).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.fcx.to_ty(ty).into()
+                        self.fcx.to_ty(ty).raw.into()
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
                         self.fcx.const_arg_to_const(&ct.value, param.def_id).into()
@@ -1225,10 +1211,7 @@ fn inferred_kind(
                             // If we have a default, then we it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.
-                            let default = tcx.bound_type_of(param.def_id);
-                            self.fcx
-                                .normalize_ty(self.span, default.subst(tcx, substs.unwrap()))
-                                .into()
+                            tcx.bound_type_of(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             // If no type arguments were provided, we have to infer them.
                             // This case also occurs as a result of some malformed input, e.g.
@@ -1250,13 +1233,13 @@ fn inferred_kind(
             }
         }
 
-        let substs = self_ctor_substs.unwrap_or_else(|| {
+        let substs_raw = self_ctor_substs.unwrap_or_else(|| {
             <dyn AstConv<'_>>::create_substs_for_generic_args(
                 tcx,
                 def_id,
                 &[],
                 has_self,
-                self_ty,
+                self_ty.map(|s| s.raw),
                 &arg_count,
                 &mut CreateCtorSubstsContext {
                     fcx: self,
@@ -1269,7 +1252,10 @@ fn inferred_kind(
         });
 
         // First, store the "user substs" for later.
-        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
+        self.write_user_type_annotation_from_substs(hir_id, def_id, substs_raw, user_self_ty);
+
+        // Normalize only after registering type annotations.
+        let substs = self.normalize(span, substs_raw);
 
         self.add_required_obligations_for_hir(span, def_id, &substs, hir_id);
 
@@ -1287,6 +1273,7 @@ fn inferred_kind(
             // with the substituted impl type.
             // This also occurs for an enum variant on a type alias.
             let impl_ty = self.normalize(span, tcx.bound_type_of(impl_def_id).subst(tcx, substs));
+            let self_ty = self.normalize(span, self_ty);
             match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
@@ -1435,9 +1422,7 @@ pub(in super::super) fn probe_instantiate_query_response(
     pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
         let mut contained_in_place = false;
 
-        while let hir::Node::Expr(parent_expr) =
-            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
-        {
+        while let hir::Node::Expr(parent_expr) = self.tcx.hir().get_parent(expr_id) {
             match &parent_expr.kind {
                 hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
                     if lhs.hir_id == expr_id {
index 877680053f09061e3966a480f9ad5b68ae5bbe12..5075d9b893b3b08e31f6e1fca1a3d38658e9898e 100644 (file)
@@ -5,11 +5,11 @@
 use crate::Expectation::*;
 use crate::TupleArgumentsFlag::*;
 use crate::{
-    struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
+    struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy,
     TupleArgumentsFlag,
 };
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -473,7 +473,7 @@ fn report_arg_errors(
         call_expr: &hir::Expr<'tcx>,
     ) {
         // Next, let's construct the error
-        let (error_span, full_call_span, ctor_of, is_method) = match &call_expr.kind {
+        let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
             hir::ExprKind::Call(
                 hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. },
                 _,
@@ -481,12 +481,16 @@ fn report_arg_errors(
                 if let Res::Def(DefKind::Ctor(of, _), _) =
                     self.typeck_results.borrow().qpath_res(qpath, *hir_id)
                 {
-                    (call_span, *span, Some(of), false)
+                    let name = match of {
+                        CtorOf::Struct => "struct",
+                        CtorOf::Variant => "enum variant",
+                    };
+                    (call_span, *span, name, false)
                 } else {
-                    (call_span, *span, None, false)
+                    (call_span, *span, "function", false)
                 }
             }
-            hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
+            hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, "function", false),
             hir::ExprKind::MethodCall(path_segment, _, _, span) => {
                 let ident_span = path_segment.ident.span;
                 let ident_span = if let Some(args) = path_segment.args {
@@ -494,17 +498,11 @@ fn report_arg_errors(
                 } else {
                     ident_span
                 };
-                // methods are never ctors
-                (*span, ident_span, None, true)
+                (*span, ident_span, "method", true)
             }
             k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
         };
         let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span);
-        let call_name = match ctor_of {
-            Some(CtorOf::Struct) => "struct",
-            Some(CtorOf::Variant) => "enum variant",
-            None => "function",
-        };
 
         // Don't print if it has error types or is just plain `_`
         fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
@@ -690,8 +688,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                         err = tcx.sess.struct_span_err_with_code(
                             full_call_span,
                             &format!(
-                                "this {} takes {}{} but {} {} supplied",
-                                call_name,
+                                "{call_name} takes {}{} but {} {} supplied",
                                 if c_variadic { "at least " } else { "" },
                                 potentially_plural_count(
                                     formal_and_expected_inputs.len(),
@@ -801,6 +798,18 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                 full_call_span,
                 format!("arguments to this {} are incorrect", call_name),
             );
+            if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) =
+                (callee_ty, &call_expr.kind)
+            {
+                // Type that would have accepted this argument if it hadn't been inferred earlier.
+                // FIXME: We leave an inference variable for now, but it'd be nice to get a more
+                // specific type to increase the accuracy of the diagnostic.
+                let expected = self.infcx.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::MiscVariable,
+                    span: full_call_span,
+                });
+                self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty);
+            }
             // Call out where the function is defined
             self.label_fn_like(
                 &mut err,
@@ -1222,31 +1231,35 @@ pub fn check_struct_path(
                 );
                 return None;
             }
-            Res::Def(DefKind::Variant, _) => match ty.kind() {
-                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)),
-                _ => bug!("unexpected type: {:?}", ty),
+            Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() {
+                Some(adt) => {
+                    Some((adt.variant_of_res(def), adt.did(), Self::user_substs_for_adt(ty)))
+                }
+                _ => bug!("unexpected type: {:?}", ty.normalized),
             },
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
             | Res::SelfTyParam { .. }
-            | Res::SelfTyAlias { .. } => match ty.kind() {
-                ty::Adt(adt, substs) if !adt.is_enum() => {
-                    Some((adt.non_enum_variant(), adt.did(), substs))
+            | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
+                Some(adt) if !adt.is_enum() => {
+                    Some((adt.non_enum_variant(), adt.did(), Self::user_substs_for_adt(ty)))
                 }
                 _ => None,
             },
             _ => bug!("unexpected definition: {:?}", def),
         };
 
-        if let Some((variant, did, substs)) = variant {
+        if let Some((variant, did, ty::UserSubsts { substs, user_self_ty })) = variant {
             debug!("check_struct_path: did={:?} substs={:?}", did, substs);
-            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
+
+            // Register type annotation.
+            self.write_user_type_annotation_from_substs(hir_id, did, substs, user_self_ty);
 
             // Check bounds on type arguments used in the path.
             self.add_required_obligations_for_hir(path_span, did, substs, hir_id);
 
-            Some((variant, ty))
+            Some((variant, ty.normalized))
         } else {
-            match ty.kind() {
+            match ty.normalized.kind() {
                 ty::Error(_) => {
                     // E0071 might be caused by a spelling error, which will have
                     // already caused an error message and probably a suggestion
@@ -1259,7 +1272,7 @@ pub fn check_struct_path(
                         path_span,
                         E0071,
                         "expected struct, variant or union type, found {}",
-                        ty.sort_string(self.tcx)
+                        ty.normalized.sort_string(self.tcx)
                     )
                     .span_label(path_span, "not a struct")
                     .emit();
@@ -1307,7 +1320,7 @@ pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
         // Type check the initializer.
         if let Some(ref init) = decl.init {
             let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init);
-            self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty);
+            self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty);
         }
 
         // Does the expected pattern type originate from an expression and what is the span?
@@ -1322,7 +1335,7 @@ pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
         // Type check the pattern. Override if necessary to avoid knock-on errors.
         self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
         let pat_ty = self.node_ty(decl.pat.hir_id);
-        self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
+        self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
 
         if let Some(blk) = decl.els {
             let previous_diverges = self.diverges.get();
@@ -1627,14 +1640,14 @@ fn overwrite_local_ty_if_err(
         &self,
         hir_id: hir::HirId,
         pat: &'tcx hir::Pat<'tcx>,
-        decl_ty: Ty<'tcx>,
         ty: Ty<'tcx>,
     ) {
         if ty.references_error() {
             // Override the types everywhere with `err()` to avoid knock on errors.
-            self.write_ty(hir_id, ty);
-            self.write_ty(pat.hir_id, ty);
-            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
+            let err = self.tcx.ty_error();
+            self.write_ty(hir_id, err);
+            self.write_ty(pat.hir_id, err);
+            let local_ty = LocalTy { decl_ty: err, revealed_ty: err };
             self.locals.borrow_mut().insert(hir_id, local_ty);
             self.locals.borrow_mut().insert(pat.hir_id, local_ty);
         }
@@ -1647,20 +1660,21 @@ fn finish_resolving_struct_path(
         qpath: &QPath<'_>,
         path_span: Span,
         hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
+    ) -> (Res, RawTy<'tcx>) {
         match *qpath {
             QPath::Resolved(ref maybe_qself, ref path) => {
-                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw);
                 let ty = <dyn AstConv<'_>>::res_to_ty(self, self_ty, path, true);
-                (path.res, ty)
+                (path.res, self.handle_raw_ty(path_span, ty))
             }
             QPath::TypeRelative(ref qself, ref segment) => {
                 let ty = self.to_ty(qself);
 
                 let result = <dyn AstConv<'_>>::associated_path_to_ty(
-                    self, hir_id, path_span, ty, qself, segment, true,
+                    self, hir_id, path_span, ty.raw, qself, segment, true,
                 );
                 let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
+                let ty = self.handle_raw_ty(path_span, ty);
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
 
                 // Write back the new resolution.
@@ -1669,7 +1683,8 @@ fn finish_resolving_struct_path(
                 (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
             }
             QPath::LangItem(lang_item, span, id) => {
-                self.resolve_lang_item_path(lang_item, span, hir_id, id)
+                let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id);
+                (res, self.handle_raw_ty(path_span, ty))
             }
         }
     }
@@ -1689,7 +1704,7 @@ pub(super) fn adjust_fulfillment_errors_for_expr_obligation(
         // even if their `ObligationCauseCode` isn't an `Expr*Obligation` kind.
         // This is important since if we adjust one span but not the other, then
         // we will have "duplicated" the error on the UI side.
-        let mut remap_cause = FxHashSet::default();
+        let mut remap_cause = FxIndexSet::default();
         let mut not_adjusted = vec![];
 
         for error in errors {
@@ -1717,6 +1732,13 @@ pub(super) fn adjust_fulfillment_errors_for_expr_obligation(
             }
         }
 
+        // Adjust any other errors that come from other cause codes, when these
+        // errors are of the same predicate as one we successfully adjusted, and
+        // when their spans overlap (suggesting they're due to the same root cause).
+        //
+        // This is because due to normalization, we often register duplicate
+        // obligations with misc obligations that are basically impossible to
+        // line back up with a useful ExprBindingObligation.
         for error in not_adjusted {
             for (span, predicate, cause) in &remap_cause {
                 if *predicate == error.obligation.predicate
@@ -1803,7 +1825,7 @@ fn adjust_fulfillment_error_for_expr_obligation(
                     hir_id: call_hir_id,
                     span: call_span,
                     ..
-                }) = hir.get(hir.get_parent_node(expr.hir_id))
+                }) = hir.get_parent(expr.hir_id)
                     && callee.hir_id == expr.hir_id
                 {
                     if self.closure_span_overlaps_error(error, *call_span) {
index 30b59da7852d46f1e96543ef7566668e00834910..6347b9a69a0077906a78c12b1f1cce0be753ba85 100644 (file)
@@ -17,8 +17,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitable};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::{self, Span};
@@ -298,11 +297,14 @@ fn projected_ty_from_poly_trait_ref(
         self.tcx().mk_projection(item_def_id, item_substs)
     }
 
-    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.has_escaping_bound_vars() {
-            ty // FIXME: normalization and escaping regions
-        } else {
-            self.normalize(span, ty)
+    fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
+        match ty.kind() {
+            ty::Adt(adt_def, _) => Some(*adt_def),
+            // FIXME(#104767): Should we handle bound regions here?
+            ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
+                self.normalize(span, ty).ty_adt_def()
+            }
+            _ => None,
         }
     }
 
@@ -310,7 +312,21 @@ fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
         self.infcx.set_tainted_by_errors(e)
     }
 
-    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
+    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
+        // FIXME: normalization and escaping regions
+        let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty };
         self.write_ty(hir_id, ty)
     }
 }
+
+/// Represents a user-provided type in the raw form (never normalized).
+///
+/// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`,
+/// and the API in this module, which expect `Ty` to be fully normalized.
+#[derive(Clone, Copy, Debug)]
+pub struct RawTy<'tcx> {
+    pub raw: Ty<'tcx>,
+
+    /// The normalized form of `raw`, stored here for efficiency.
+    pub normalized: Ty<'tcx>,
+}
index 9a7d753e66b8eafd8f60edbecae8e88f2ab8a2f2..236bdc60e677d8899dc0415b68d0fe206d5d89d0 100644 (file)
@@ -19,6 +19,7 @@
     TypeVisitable,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -31,7 +32,7 @@ pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
         self.typeck_results
             .borrow()
             .liberated_fn_sigs()
-            .get(self.tcx.hir().get_parent_node(self.body_id))
+            .get(self.tcx.hir().parent_id(self.body_id))
             .copied()
     }
 
@@ -641,7 +642,7 @@ pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
                 // Check if the parent expression is a call to Pin::new.  If it
                 // is and we were expecting a Box, ergo Pin<Box<expected>>, we
                 // can suggest Box::pin.
-                let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+                let parent = self.tcx.hir().parent_id(expr.hir_id);
                 let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) = self.tcx.hir().find(parent) else {
                     return false;
                 };
@@ -973,7 +974,7 @@ pub(in super::super) fn suggest_missing_parentheses(
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
     ) -> bool {
-        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
         if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
             // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
             err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
@@ -1013,6 +1014,36 @@ pub(crate) fn suggest_block_to_brackets_peeling_refs(
         }
     }
 
+    pub(crate) fn suggest_clone_for_ref(
+        &self,
+        diag: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        expr_ty: Ty<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> bool {
+        if let ty::Ref(_, inner_ty, hir::Mutability::Not) = expr_ty.kind()
+            && let Some(clone_trait_def) = self.tcx.lang_items().clone_trait()
+            && expected_ty == *inner_ty
+            && self
+                .infcx
+                .type_implements_trait(
+                    clone_trait_def,
+                    [self.tcx.erase_regions(expected_ty)],
+                    self.param_env
+                )
+                .must_apply_modulo_regions()
+          {
+              diag.span_suggestion_verbose(
+                  expr.span.shrink_to_hi(),
+                  "consider using clone here",
+                  ".clone()",
+                  Applicability::MachineApplicable,
+              );
+              return true;
+          }
+        false
+    }
+
     pub(crate) fn suggest_copied_or_cloned(
         &self,
         diag: &mut Diagnostic,
@@ -1259,6 +1290,31 @@ pub(crate) fn suggest_floating_point_literal(
                 );
                 true
             }
+            ExprKind::Lit(Spanned {
+                node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
+                span,
+            }) => {
+                let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; };
+                if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
+                    return false;
+                }
+                if snippet.len() <= 5 || !snippet.is_char_boundary(snippet.len() - 3) {
+                    return false;
+                }
+                let (_, suffix) = snippet.split_at(snippet.len() - 3);
+                let value = match suffix {
+                    "f32" => (lit - 0xf32) / (16 * 16 * 16),
+                    "f64" => (lit - 0xf64) / (16 * 16 * 16),
+                    _ => return false,
+                };
+                err.span_suggestions(
+                    expr.span,
+                    "rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float",
+                    [format!("0x{value:X} as {suffix}"), format!("{value}_{suffix}")],
+                    Applicability::MaybeIncorrect,
+                );
+                true
+            }
             _ => false,
         }
     }
index 9a096f24fac0d965d39546ceaf52e4e529e33f27..15dd3412c34093e062eb5b74aa36a77fd5a3010a 100644 (file)
@@ -77,7 +77,8 @@ fn declare(&mut self, decl: Declaration<'tcx>) {
             Some(ref ty) => {
                 let o_ty = self.fcx.to_ty(&ty);
 
-                let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty));
+                let c_ty =
+                    self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
                 debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
                 self.fcx
                     .typeck_results
@@ -85,7 +86,7 @@ fn declare(&mut self, decl: Declaration<'tcx>) {
                     .user_provided_types_mut()
                     .insert(ty.hir_id, c_ty);
 
-                Some(LocalTy { decl_ty: o_ty, revealed_ty: o_ty })
+                Some(LocalTy { decl_ty: o_ty.normalized, revealed_ty: o_ty.normalized })
             }
             None => None,
         };
index bfe95852aa7b408cd22fc5f6912064fe2eebd67b..472205be7b5e3e81a96f1438b97d6865a691786c 100644 (file)
@@ -140,7 +140,7 @@ fn consume(
         diag_expr_id: HirId,
     ) {
         let hir = self.tcx.hir();
-        let parent = match hir.find_parent_node(place_with_id.hir_id) {
+        let parent = match hir.opt_parent_id(place_with_id.hir_id) {
             Some(parent) => parent,
             None => place_with_id.hir_id,
         };
index b06927f9662be7aeb09882ab6b7ec860a1a94061..69929589541f5e0de0078c64806dc79bea8cdb96 100644 (file)
@@ -224,7 +224,7 @@ fn typeck_with_fallback<'tcx>(
                     _ => None,
                 })
                 .unwrap_or_else(|| match tcx.hir().get(id) {
-                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().parent_id(id)) {
                         Node::Expr(&hir::Expr {
                             kind: hir::ExprKind::ConstBlock(ref anon_const),
                             ..
@@ -240,10 +240,8 @@ fn typeck_with_fallback<'tcx>(
                         }),
                         Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
                         | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
-                            let operand_ty = asm
-                                .operands
-                                .iter()
-                                .filter_map(|(op, _op_sp)| match op {
+                            let operand_ty =
+                                asm.operands.iter().find_map(|(op, _op_sp)| match op {
                                     hir::InlineAsmOperand::Const { anon_const }
                                         if anon_const.hir_id == id =>
                                     {
@@ -259,8 +257,7 @@ fn typeck_with_fallback<'tcx>(
                                         }))
                                     }
                                     _ => None,
-                                })
-                                .next();
+                                });
                             operand_ty.unwrap_or_else(fallback)
                         }
                         _ => fallback(),
@@ -300,7 +297,7 @@ fn typeck_with_fallback<'tcx>(
         fcx.resolve_generator_interiors(def_id.to_def_id());
 
         for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
-            let ty = fcx.normalize_ty(span, ty);
+            let ty = fcx.normalize(span, ty);
             fcx.require_type_is_sized(ty, span, code);
         }
 
index 218c54688aa3e959a187f7b69aded369e9ab8a99..a2c6e246610b21c391782f20d40593437b5f8272 100644 (file)
@@ -12,7 +12,8 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{self, SubstsRef};
 use rustc_middle::ty::{self, GenericParamDefKind, Ty};
-use rustc_span::Span;
+use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType};
+use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
 use std::iter;
@@ -372,7 +373,7 @@ fn provided_kind(
                             .into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.cfcx.to_ty(ty).into()
+                        self.cfcx.to_ty(ty).raw.into()
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
                         self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
@@ -397,7 +398,8 @@ fn inferred_kind(
                 self.cfcx.var_for_def(self.cfcx.span, param)
             }
         }
-        <dyn AstConv<'_>>::create_substs_for_generic_args(
+
+        let substs = <dyn AstConv<'_>>::create_substs_for_generic_args(
             self.tcx,
             pick.item.def_id,
             parent_substs,
@@ -405,7 +407,47 @@ fn inferred_kind(
             None,
             &arg_count_correct,
             &mut MethodSubstsCtxt { cfcx: self, pick, seg },
-        )
+        );
+
+        // When the method is confirmed, the `substs` includes
+        // parameters from not just the method, but also the impl of
+        // the method -- in particular, the `Self` type will be fully
+        // resolved. However, those are not something that the "user
+        // specified" -- i.e., those types come from the inferred type
+        // of the receiver, not something the user wrote. So when we
+        // create the user-substs, we want to replace those earlier
+        // types with just the types that the user actually wrote --
+        // that is, those that appear on the *method itself*.
+        //
+        // As an example, if the user wrote something like
+        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
+        // type of `foo` (possibly adjusted), but we don't want to
+        // include that. We want just the `[_, u32]` part.
+        if !substs.is_empty() && !generics.params.is_empty() {
+            let user_type_annotation = self.probe(|_| {
+                let user_substs = UserSubsts {
+                    substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| {
+                        let i = param.index as usize;
+                        if i < generics.parent_count {
+                            self.fcx.var_for_def(DUMMY_SP, param)
+                        } else {
+                            substs[i]
+                        }
+                    }),
+                    user_self_ty: None, // not relevant here
+                };
+
+                self.fcx.canonicalize_user_type_annotation(UserType::TypeOf(
+                    pick.item.def_id,
+                    user_substs,
+                ))
+            });
+
+            debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation);
+            self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
+        }
+
+        self.normalize(self.span, substs)
     }
 
     fn unify_receivers(
index fddb8a458a7d5f0716a6ba25f7339849a1196eb4..d276bcdb81e3e68e726397420be8d55b0b77d5c5 100644 (file)
@@ -11,7 +11,7 @@
 pub use self::MethodError::*;
 
 use crate::errors::OpMethodGenericParams;
-use crate::{Expectation, FnCtxt};
+use crate::FnCtxt;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
@@ -57,7 +57,12 @@ pub enum MethodError<'tcx> {
     PrivateMatch(DefKind, DefId, Vec<DefId>),
 
     // Found a `Self: Sized` bound where `Self` is a trait object.
-    IllegalSizedBound(Vec<DefId>, bool, Span),
+    IllegalSizedBound {
+        candidates: Vec<DefId>,
+        needs_mut: bool,
+        bound_span: Span,
+        self_expr: &'tcx hir::Expr<'tcx>,
+    },
 
     // Found a match, but the return type is wrong
     BadReturnType,
@@ -112,7 +117,7 @@ pub fn method_exists(
             Err(NoMatch(..)) => false,
             Err(Ambiguity(..)) => true,
             Err(PrivateMatch(..)) => allow_private,
-            Err(IllegalSizedBound(..)) => true,
+            Err(IllegalSizedBound { .. }) => true,
             Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
         }
     }
@@ -236,7 +241,7 @@ pub fn lookup_method(
                     _ => Vec::new(),
                 };
 
-            return Err(IllegalSizedBound(candidates, needs_mut, span));
+            return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
         }
 
         Ok(result.callee)
@@ -264,7 +269,7 @@ pub fn lookup_probe(
 
     pub(super) fn obligation_for_method(
         &self,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         opt_input_types: Option<&[Ty<'tcx>]>,
@@ -282,71 +287,19 @@ pub(super) fn obligation_for_method(
                     }
                 }
             }
-            self.var_for_def(span, param)
+            self.var_for_def(cause.span, param)
         });
 
         let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        (
-            traits::Obligation::misc(
-                self.tcx,
-                span,
-                self.body_id,
-                self.param_env,
-                poly_trait_ref.without_const(),
-            ),
-            substs,
-        )
-    }
-
-    pub(super) fn obligation_for_op_method(
-        &self,
-        span: Span,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        opt_input_type: Option<Ty<'tcx>>,
-        opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
-        expected: Expectation<'tcx>,
-    ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
-    {
-        // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
-            match param.kind {
-                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
-                GenericParamDefKind::Type { .. } => {
-                    if param.index == 0 {
-                        return self_ty.into();
-                    } else if let Some(input_type) = opt_input_type {
-                        return input_type.into();
-                    }
-                }
-            }
-            self.var_for_def(span, param)
-        });
-
-        let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
-
-        // Construct an obligation
-        let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
-
         (
             traits::Obligation::new(
                 self.tcx,
-                traits::ObligationCause::new(
-                    span,
-                    self.body_id,
-                    traits::BinOp {
-                        rhs_span: opt_input_expr.map(|expr| expr.span),
-                        is_lit: opt_input_expr
-                            .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
-                        output_ty,
-                    },
-                ),
+                cause,
                 self.param_env,
-                poly_trait_ref,
+                poly_trait_ref.without_const(),
             ),
             substs,
         )
@@ -357,55 +310,18 @@ pub(super) fn obligation_for_op_method(
     /// In particular, it doesn't really do any probing: it simply constructs
     /// an obligation for a particular trait with the given self type and checks
     /// whether that trait is implemented.
-    #[instrument(level = "debug", skip(self, span))]
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn lookup_method_in_trait(
         &self,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         m_name: Ident,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         opt_input_types: Option<&[Ty<'tcx>]>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         let (obligation, substs) =
-            self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
-        self.construct_obligation_for_trait(
-            span,
-            m_name,
-            trait_def_id,
-            obligation,
-            substs,
-            None,
-            false,
-        )
-    }
-
-    pub(super) fn lookup_op_method_in_trait(
-        &self,
-        span: Span,
-        m_name: Ident,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        opt_input_type: Option<Ty<'tcx>>,
-        opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
-        expected: Expectation<'tcx>,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        let (obligation, substs) = self.obligation_for_op_method(
-            span,
-            trait_def_id,
-            self_ty,
-            opt_input_type,
-            opt_input_expr,
-            expected,
-        );
-        self.construct_obligation_for_trait(
-            span,
-            m_name,
-            trait_def_id,
-            obligation,
-            substs,
-            opt_input_expr,
-            true,
-        )
+            self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
+        self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
     }
 
     // FIXME(#18741): it seems likely that we can consolidate some of this
@@ -413,13 +329,10 @@ pub(super) fn lookup_op_method_in_trait(
     // of this method is basically the same as confirmation.
     fn construct_obligation_for_trait(
         &self,
-        span: Span,
         m_name: Ident,
         trait_def_id: DefId,
         obligation: traits::PredicateObligation<'tcx>,
         substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
-        opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
-        is_op: bool,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         debug!(?obligation);
 
@@ -435,7 +348,7 @@ fn construct_obligation_for_trait(
         let tcx = self.tcx;
         let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
             tcx.sess.delay_span_bug(
-                span,
+                obligation.cause.span,
                 "operator trait does not have corresponding operator method",
             );
             return None;
@@ -461,24 +374,11 @@ fn construct_obligation_for_trait(
         // with bound regions.
         let fn_sig = tcx.bound_fn_sig(def_id);
         let fn_sig = fn_sig.subst(self.tcx, substs);
-        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
-
-        let cause = if is_op {
-            ObligationCause::new(
-                span,
-                self.body_id,
-                traits::BinOp {
-                    rhs_span: opt_input_expr.map(|expr| expr.span),
-                    is_lit: opt_input_expr
-                        .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
-                    output_ty: None,
-                },
-            )
-        } else {
-            traits::ObligationCause::misc(span, self.body_id)
-        };
+        let fn_sig =
+            self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
 
-        let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
+        let InferOk { value, obligations: o } =
+            self.at(&obligation.cause, self.param_env).normalize(fn_sig);
         let fn_sig = {
             obligations.extend(o);
             value
@@ -494,7 +394,8 @@ fn construct_obligation_for_trait(
         // any late-bound regions appearing in its bounds.
         let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
 
-        let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds);
+        let InferOk { value, obligations: o } =
+            self.at(&obligation.cause, self.param_env).normalize(bounds);
         let bounds = {
             obligations.extend(o);
             value
@@ -502,7 +403,7 @@ fn construct_obligation_for_trait(
 
         assert!(!bounds.has_escaping_bound_vars());
 
-        let predicates_cause = cause.clone();
+        let predicates_cause = obligation.cause.clone();
         obligations.extend(traits::predicates_for_generics(
             move |_, _| predicates_cause.clone(),
             self.param_env,
@@ -517,7 +418,7 @@ fn construct_obligation_for_trait(
         );
         obligations.push(traits::Obligation::new(
             tcx,
-            cause,
+            obligation.cause,
             self.param_env,
             ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
         ));
index dea14dd93d6acd15e0ec4199ad0f677b5461ce6b..3d6c2119bea333e568dbd49f026bd343f1bdb32c 100644 (file)
@@ -341,8 +341,7 @@ fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Opt
         // Find an identifier with which this trait was imported (note that `_` doesn't count).
         let any_id = import_items
             .iter()
-            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
-            .next();
+            .find_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None });
         if let Some(any_id) = any_id {
             if any_id.name == Empty {
                 // Glob import, so just use its name.
index b9e7830bf079214af2a29491fff1ab458fbee011..2daf1979ee5e69d51642a7588f38aa29d6a12272 100644 (file)
@@ -97,7 +97,7 @@ fn deref(&self) -> &Self::Target {
 }
 
 #[derive(Debug, Clone)]
-struct Candidate<'tcx> {
+pub(crate) struct Candidate<'tcx> {
     // Candidates are (I'm not quite sure, but they are mostly) basically
     // some metadata on top of a `ty::AssocItem` (without substs).
     //
@@ -131,13 +131,13 @@ struct Candidate<'tcx> {
     // if `T: Sized`.
     xform_self_ty: Ty<'tcx>,
     xform_ret_ty: Option<Ty<'tcx>>,
-    item: ty::AssocItem,
-    kind: CandidateKind<'tcx>,
-    import_ids: SmallVec<[LocalDefId; 1]>,
+    pub(crate) item: ty::AssocItem,
+    pub(crate) kind: CandidateKind<'tcx>,
+    pub(crate) import_ids: SmallVec<[LocalDefId; 1]>,
 }
 
 #[derive(Debug, Clone)]
-enum CandidateKind<'tcx> {
+pub(crate) enum CandidateKind<'tcx> {
     InherentImplCandidate(
         SubstsRef<'tcx>,
         // Normalize obligations
@@ -322,6 +322,36 @@ pub fn probe_for_name(
         )
     }
 
+    #[instrument(level = "debug", skip(self))]
+    pub(crate) fn probe_for_name_many(
+        &self,
+        mode: Mode,
+        item_name: Ident,
+        is_suggestion: IsSuggestion,
+        self_ty: Ty<'tcx>,
+        scope_expr_id: hir::HirId,
+        scope: ProbeScope,
+    ) -> Vec<Candidate<'tcx>> {
+        self.probe_op(
+            item_name.span,
+            mode,
+            Some(item_name),
+            None,
+            is_suggestion,
+            self_ty,
+            scope_expr_id,
+            scope,
+            |probe_cx| {
+                Ok(probe_cx
+                    .inherent_candidates
+                    .into_iter()
+                    .chain(probe_cx.extension_candidates)
+                    .collect())
+            },
+        )
+        .unwrap()
+    }
+
     fn probe_op<OP, R>(
         &'a self,
         span: Span,
@@ -943,6 +973,9 @@ fn assemble_extension_candidates_for_trait(
             });
         } else {
             debug_assert!(self.tcx.is_trait(trait_def_id));
+            if self.tcx.trait_is_auto(trait_def_id) {
+                return;
+            }
             for item in self.impl_or_trait_item(trait_def_id) {
                 // Check whether `trait_def_id` defines a method with suitable name.
                 if !self.has_applicable_self(&item) {
@@ -1078,7 +1111,7 @@ fn pick_all_method(
                 // a raw pointer
                 !step.self_ty.references_error() && !step.from_unsafe_deref
             })
-            .flat_map(|step| {
+            .find_map(|step| {
                 let InferOk { value: self_ty, obligations: _ } = self
                     .fcx
                     .probe_instantiate_query_response(
@@ -1114,7 +1147,6 @@ fn pick_all_method(
                         })
                     })
             })
-            .next()
     }
 
     /// For each type `T` in the step list, this attempts to find a method where
index 7c5a9a333feba56da059e18d4b90b1cf1563db56..536c4270659582b17f32581b0f7488f405cb2381 100644 (file)
@@ -102,7 +102,7 @@ fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
 
     pub fn report_method_error(
         &self,
-        mut span: Span,
+        span: Span,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
@@ -114,921 +114,24 @@ pub fn report_method_error(
             return None;
         }
 
-        let report_candidates = |span: Span,
-                                 err: &mut Diagnostic,
-                                 sources: &mut Vec<CandidateSource>,
-                                 sugg_span: Option<Span>| {
-            sources.sort();
-            sources.dedup();
-            // Dynamic limit to avoid hiding just one candidate, which is silly.
-            let limit = if sources.len() == 5 { 5 } else { 4 };
-
-            for (idx, source) in sources.iter().take(limit).enumerate() {
-                match *source {
-                    CandidateSource::Impl(impl_did) => {
-                        // Provide the best span we can. Use the item, if local to crate, else
-                        // the impl, if local to crate (item may be defaulted), else nothing.
-                        let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
-                            let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
-                            self.associated_value(impl_trait_ref.def_id, item_name)
-                        }) else {
-                            continue;
-                        };
-
-                        let note_span = if item.def_id.is_local() {
-                            Some(self.tcx.def_span(item.def_id))
-                        } else if impl_did.is_local() {
-                            Some(self.tcx.def_span(impl_did))
-                        } else {
-                            None
-                        };
-
-                        let impl_ty = self.tcx.at(span).type_of(impl_did);
-
-                        let insertion = match self.tcx.impl_trait_ref(impl_did) {
-                            None => String::new(),
-                            Some(trait_ref) => format!(
-                                " of the trait `{}`",
-                                self.tcx.def_path_str(trait_ref.def_id)
-                            ),
-                        };
-
-                        let (note_str, idx) = if sources.len() > 1 {
-                            (
-                                format!(
-                                    "candidate #{} is defined in an impl{} for the type `{}`",
-                                    idx + 1,
-                                    insertion,
-                                    impl_ty,
-                                ),
-                                Some(idx + 1),
-                            )
-                        } else {
-                            (
-                                format!(
-                                    "the candidate is defined in an impl{} for the type `{}`",
-                                    insertion, impl_ty,
-                                ),
-                                None,
-                            )
-                        };
-                        if let Some(note_span) = note_span {
-                            // We have a span pointing to the method. Show note with snippet.
-                            err.span_note(note_span, &note_str);
-                        } else {
-                            err.note(&note_str);
-                        }
-                        if let Some(sugg_span) = sugg_span
-                            && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
-                            let path = self.tcx.def_path_str(trait_ref.def_id);
-
-                            let ty = match item.kind {
-                                ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
-                                ty::AssocKind::Fn => self
-                                    .tcx
-                                    .fn_sig(item.def_id)
-                                    .inputs()
-                                    .skip_binder()
-                                    .get(0)
-                                    .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
-                                    .copied()
-                                    .unwrap_or(rcvr_ty),
-                            };
-                            print_disambiguation_help(
-                                item_name,
-                                args,
-                                err,
-                                path,
-                                ty,
-                                item.kind,
-                                item.def_id,
-                                sugg_span,
-                                idx,
-                                self.tcx.sess.source_map(),
-                                item.fn_has_self_parameter,
-                            );
-                        }
-                    }
-                    CandidateSource::Trait(trait_did) => {
-                        let Some(item) = self.associated_value(trait_did, item_name) else { continue };
-                        let item_span = self.tcx.def_span(item.def_id);
-                        let idx = if sources.len() > 1 {
-                            let msg = &format!(
-                                "candidate #{} is defined in the trait `{}`",
-                                idx + 1,
-                                self.tcx.def_path_str(trait_did)
-                            );
-                            err.span_note(item_span, msg);
-                            Some(idx + 1)
-                        } else {
-                            let msg = &format!(
-                                "the candidate is defined in the trait `{}`",
-                                self.tcx.def_path_str(trait_did)
-                            );
-                            err.span_note(item_span, msg);
-                            None
-                        };
-                        if let Some(sugg_span) = sugg_span {
-                            let path = self.tcx.def_path_str(trait_did);
-                            print_disambiguation_help(
-                                item_name,
-                                args,
-                                err,
-                                path,
-                                rcvr_ty,
-                                item.kind,
-                                item.def_id,
-                                sugg_span,
-                                idx,
-                                self.tcx.sess.source_map(),
-                                item.fn_has_self_parameter,
-                            );
-                        }
-                    }
-                }
-            }
-            if sources.len() > limit {
-                err.note(&format!("and {} others", sources.len() - limit));
-            }
-        };
-
         let sugg_span = if let SelfSource::MethodCall(expr) = source {
             // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
-            self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
+            self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)).span
         } else {
             span
         };
 
         match error {
-            MethodError::NoMatch(NoMatchData {
-                mut static_candidates,
-                unsatisfied_predicates,
-                out_of_scope_traits,
-                lev_candidate,
-                mode,
-            }) => {
-                let tcx = self.tcx;
-
-                let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
-                let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
-                let is_method = mode == Mode::MethodCall;
-                let item_kind = if is_method {
-                    "method"
-                } else if rcvr_ty.is_enum() {
-                    "variant or associated item"
-                } else {
-                    match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
-                        (Some(name), false) if name.is_lowercase() => "function or associated item",
-                        (Some(_), false) => "associated item",
-                        (Some(_), true) | (None, false) => "variant or associated item",
-                        (None, true) => "variant",
-                    }
-                };
-
-                if self.suggest_wrapping_range_with_parens(
-                    tcx, rcvr_ty, source, span, item_name, &ty_str,
-                ) || self.suggest_constraining_numerical_ty(
-                    tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
-                ) {
-                    return None;
-                }
-                span = item_name.span;
-
-                // Don't show generic arguments when the method can't be found in any implementation (#81576).
-                let mut ty_str_reported = ty_str.clone();
-                if let ty::Adt(_, generics) = rcvr_ty.kind() {
-                    if generics.len() > 0 {
-                        let mut autoderef = self.autoderef(span, rcvr_ty);
-                        let candidate_found = autoderef.any(|(ty, _)| {
-                            if let ty::Adt(adt_def, _) = ty.kind() {
-                                self.tcx
-                                    .inherent_impls(adt_def.did())
-                                    .iter()
-                                    .filter_map(|def_id| self.associated_value(*def_id, item_name))
-                                    .count()
-                                    >= 1
-                            } else {
-                                false
-                            }
-                        });
-                        let has_deref = autoderef.step_count() > 0;
-                        if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
-                            if let Some((path_string, _)) = ty_str.split_once('<') {
-                                ty_str_reported = path_string.to_string();
-                            }
-                        }
-                    }
-                }
-
-                let mut err = struct_span_err!(
-                    tcx.sess,
+            MethodError::NoMatch(mut no_match_data) => {
+                return self.report_no_match_method_error(
                     span,
-                    E0599,
-                    "no {} named `{}` found for {} `{}` in the current scope",
-                    item_kind,
+                    rcvr_ty,
                     item_name,
-                    rcvr_ty.prefix_string(self.tcx),
-                    ty_str_reported,
+                    source,
+                    args,
+                    sugg_span,
+                    &mut no_match_data,
                 );
-                if rcvr_ty.references_error() {
-                    err.downgrade_to_delayed_bug();
-                }
-
-                if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
-                    self.suggest_await_before_method(
-                        &mut err, item_name, rcvr_ty, cal, span,
-                    );
-                }
-                if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
-                    err.span_suggestion(
-                        span.shrink_to_lo(),
-                        "you are looking for the module in `std`, not the primitive type",
-                        "std::",
-                        Applicability::MachineApplicable,
-                    );
-                }
-                if let ty::RawPtr(_) = &rcvr_ty.kind() {
-                    err.note(
-                        "try using `<*const T>::as_ref()` to get a reference to the \
-                         type behind the pointer: https://doc.rust-lang.org/std/\
-                         primitive.pointer.html#method.as_ref",
-                    );
-                    err.note(
-                        "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
-                         to invalid or uninitialized memory is undefined behavior",
-                    );
-                }
-
-                let ty_span = match rcvr_ty.kind() {
-                    ty::Param(param_type) => Some(
-                        param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
-                    ),
-                    ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
-                    _ => None,
-                };
-                if let Some(span) = ty_span {
-                    err.span_label(
-                        span,
-                        format!(
-                            "{item_kind} `{item_name}` not found for this {}",
-                            rcvr_ty.prefix_string(self.tcx)
-                        ),
-                    );
-                }
-
-                if let SelfSource::MethodCall(rcvr_expr) = source {
-                    self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
-                        let call_expr = self
-                            .tcx
-                            .hir()
-                            .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
-                        let probe = self.lookup_probe(
-                            item_name,
-                            output_ty,
-                            call_expr,
-                            ProbeScope::AllTraits,
-                        );
-                        probe.is_ok()
-                    });
-                }
-
-                let mut custom_span_label = false;
-
-                if !static_candidates.is_empty() {
-                    err.note(
-                        "found the following associated functions; to be used as methods, \
-                         functions must have a `self` parameter",
-                    );
-                    err.span_label(span, "this is an associated function, not a method");
-                    custom_span_label = true;
-                }
-                if static_candidates.len() == 1 {
-                    self.suggest_associated_call_syntax(
-                        &mut err,
-                        &static_candidates,
-                        rcvr_ty,
-                        source,
-                        item_name,
-                        args,
-                        sugg_span,
-                    );
-
-                    report_candidates(span, &mut err, &mut static_candidates, None);
-                } else if static_candidates.len() > 1 {
-                    report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span));
-                }
-
-                let mut bound_spans = vec![];
-                let mut restrict_type_params = false;
-                let mut unsatisfied_bounds = false;
-                if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
-                    let msg = "consider using `len` instead";
-                    if let SelfSource::MethodCall(_expr) = source {
-                        err.span_suggestion_short(
-                            span,
-                            msg,
-                            "len",
-                            Applicability::MachineApplicable,
-                        );
-                    } else {
-                        err.span_label(span, msg);
-                    }
-                    if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
-                        let iterator_trait = self.tcx.def_path_str(iterator_trait);
-                        err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
-                    }
-                } else if !unsatisfied_predicates.is_empty() {
-                    let mut type_params = FxHashMap::default();
-
-                    // Pick out the list of unimplemented traits on the receiver.
-                    // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
-                    let mut unimplemented_traits = FxHashMap::default();
-                    let mut unimplemented_traits_only = true;
-                    for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
-                        if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
-                            (predicate.kind().skip_binder(), cause.as_ref())
-                        {
-                            if p.trait_ref.self_ty() != rcvr_ty {
-                                // This is necessary, not just to keep the errors clean, but also
-                                // because our derived obligations can wind up with a trait ref that
-                                // requires a different param_env to be correctly compared.
-                                continue;
-                            }
-                            unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
-                                predicate.kind().rebind(p.trait_ref),
-                                Obligation {
-                                    cause: cause.clone(),
-                                    param_env: self.param_env,
-                                    predicate: *predicate,
-                                    recursion_depth: 0,
-                                },
-                            ));
-                        }
-                    }
-
-                    // Make sure that, if any traits other than the found ones were involved,
-                    // we don't don't report an unimplemented trait.
-                    // We don't want to say that `iter::Cloned` is not an iterator, just
-                    // because of some non-Clone item being iterated over.
-                    for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
-                        match predicate.kind().skip_binder() {
-                            ty::PredicateKind::Clause(ty::Clause::Trait(p))
-                                if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
-                            _ => {
-                                unimplemented_traits_only = false;
-                                break;
-                            }
-                        }
-                    }
-
-                    let mut collect_type_param_suggestions =
-                        |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
-                            // We don't care about regions here, so it's fine to skip the binder here.
-                            if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
-                                (self_ty.kind(), parent_pred.kind().skip_binder())
-                            {
-                                let hir = self.tcx.hir();
-                                let node = match p.trait_ref.self_ty().kind() {
-                                    ty::Param(_) => {
-                                        // Account for `fn` items like in `issue-35677.rs` to
-                                        // suggest restricting its type params.
-                                        let parent_body =
-                                            hir.body_owner(hir::BodyId { hir_id: self.body_id });
-                                        Some(hir.get(parent_body))
-                                    }
-                                    ty::Adt(def, _) => {
-                                        def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
-                                    }
-                                    _ => None,
-                                };
-                                if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
-                                    if let Some(g) = kind.generics() {
-                                        let key = (
-                                            g.tail_span_for_predicate_suggestion(),
-                                            g.add_where_or_trailing_comma(),
-                                        );
-                                        type_params
-                                            .entry(key)
-                                            .or_insert_with(FxHashSet::default)
-                                            .insert(obligation.to_owned());
-                                    }
-                                }
-                            }
-                        };
-                    let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
-                        let msg = format!(
-                            "doesn't satisfy `{}`",
-                            if obligation.len() > 50 { quiet } else { obligation }
-                        );
-                        match &self_ty.kind() {
-                            // Point at the type that couldn't satisfy the bound.
-                            ty::Adt(def, _) => {
-                                bound_spans.push((self.tcx.def_span(def.did()), msg))
-                            }
-                            // Point at the trait object that couldn't satisfy the bound.
-                            ty::Dynamic(preds, _, _) => {
-                                for pred in preds.iter() {
-                                    match pred.skip_binder() {
-                                        ty::ExistentialPredicate::Trait(tr) => bound_spans
-                                            .push((self.tcx.def_span(tr.def_id), msg.clone())),
-                                        ty::ExistentialPredicate::Projection(_)
-                                        | ty::ExistentialPredicate::AutoTrait(_) => {}
-                                    }
-                                }
-                            }
-                            // Point at the closure that couldn't satisfy the bound.
-                            ty::Closure(def_id, _) => bound_spans.push((
-                                tcx.def_span(*def_id),
-                                format!("doesn't satisfy `{}`", quiet),
-                            )),
-                            _ => {}
-                        }
-                    };
-                    let mut format_pred = |pred: ty::Predicate<'tcx>| {
-                        let bound_predicate = pred.kind();
-                        match bound_predicate.skip_binder() {
-                            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
-                                let pred = bound_predicate.rebind(pred);
-                                // `<Foo as Iterator>::Item = String`.
-                                let projection_ty = pred.skip_binder().projection_ty;
-
-                                let substs_with_infer_self = tcx.mk_substs(
-                                    iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
-                                        .chain(projection_ty.substs.iter().skip(1)),
-                                );
-
-                                let quiet_projection_ty =
-                                    tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
-
-                                let term = pred.skip_binder().term;
-
-                                let obligation = format!("{} = {}", projection_ty, term);
-                                let quiet = with_forced_trimmed_paths!(format!(
-                                    "{} = {}",
-                                    quiet_projection_ty, term
-                                ));
-
-                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
-                                Some((obligation, projection_ty.self_ty()))
-                            }
-                            ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
-                                let p = poly_trait_ref.trait_ref;
-                                let self_ty = p.self_ty();
-                                let path = p.print_only_trait_path();
-                                let obligation = format!("{}: {}", self_ty, path);
-                                let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
-                                bound_span_label(self_ty, &obligation, &quiet);
-                                Some((obligation, self_ty))
-                            }
-                            _ => None,
-                        }
-                    };
-
-                    // Find all the requirements that come from a local `impl` block.
-                    let mut skip_list: FxHashSet<_> = Default::default();
-                    let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
-                    for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
-                        .iter()
-                        .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
-                        .filter_map(|(p, parent, c)| match c.code() {
-                            ObligationCauseCode::ImplDerivedObligation(data) => {
-                                Some((&data.derived, p, parent, data.impl_def_id, data))
-                            }
-                            _ => None,
-                        })
-                    {
-                        let parent_trait_ref = data.parent_trait_pred;
-                        let path = parent_trait_ref.print_modifiers_and_trait_path();
-                        let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
-                        let unsatisfied_msg = "unsatisfied trait bound introduced here";
-                        let derive_msg =
-                            "unsatisfied trait bound introduced in this `derive` macro";
-                        match self.tcx.hir().get_if_local(impl_def_id) {
-                            // Unmet obligation comes from a `derive` macro, point at it once to
-                            // avoid multiple span labels pointing at the same place.
-                            Some(Node::Item(hir::Item {
-                                kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
-                                ..
-                            })) if matches!(
-                                self_ty.span.ctxt().outer_expn_data().kind,
-                                ExpnKind::Macro(MacroKind::Derive, _)
-                            ) || matches!(
-                                of_trait.as_ref().map(|t| t
-                                    .path
-                                    .span
-                                    .ctxt()
-                                    .outer_expn_data()
-                                    .kind),
-                                Some(ExpnKind::Macro(MacroKind::Derive, _))
-                            ) =>
-                            {
-                                let span = self_ty.span.ctxt().outer_expn_data().call_site;
-                                let mut spans: MultiSpan = span.into();
-                                spans.push_span_label(span, derive_msg);
-                                let entry = spanned_predicates.entry(spans);
-                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
-                            }
-
-                            // Unmet obligation coming from an `impl`.
-                            Some(Node::Item(hir::Item {
-                                kind:
-                                    hir::ItemKind::Impl(hir::Impl {
-                                        of_trait, self_ty, generics, ..
-                                    }),
-                                span: item_span,
-                                ..
-                            })) => {
-                                let sized_pred =
-                                    unsatisfied_predicates.iter().any(|(pred, _, _)| {
-                                        match pred.kind().skip_binder() {
-                                            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
-                                                Some(pred.def_id())
-                                                    == self.tcx.lang_items().sized_trait()
-                                                    && pred.polarity == ty::ImplPolarity::Positive
-                                            }
-                                            _ => false,
-                                        }
-                                    });
-                                for param in generics.params {
-                                    if param.span == cause.span && sized_pred {
-                                        let (sp, sugg) = match param.colon_span {
-                                            Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
-                                            None => (param.span.shrink_to_hi(), ": ?Sized"),
-                                        };
-                                        err.span_suggestion_verbose(
-                                            sp,
-                                            "consider relaxing the type parameter's implicit \
-                                             `Sized` bound",
-                                            sugg,
-                                            Applicability::MachineApplicable,
-                                        );
-                                    }
-                                }
-                                if let Some(pred) = parent_p {
-                                    // Done to add the "doesn't satisfy" `span_label`.
-                                    let _ = format_pred(*pred);
-                                }
-                                skip_list.insert(p);
-                                let mut spans = if cause.span != *item_span {
-                                    let mut spans: MultiSpan = cause.span.into();
-                                    spans.push_span_label(cause.span, unsatisfied_msg);
-                                    spans
-                                } else {
-                                    let mut spans = Vec::with_capacity(2);
-                                    if let Some(trait_ref) = of_trait {
-                                        spans.push(trait_ref.path.span);
-                                    }
-                                    spans.push(self_ty.span);
-                                    spans.into()
-                                };
-                                if let Some(trait_ref) = of_trait {
-                                    spans.push_span_label(trait_ref.path.span, "");
-                                }
-                                spans.push_span_label(self_ty.span, "");
-
-                                let entry = spanned_predicates.entry(spans);
-                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
-                            }
-                            Some(Node::Item(hir::Item {
-                                kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
-                                span: item_span,
-                                ..
-                            })) => {
-                                tcx.sess.delay_span_bug(
-                                        *item_span,
-                                        "auto trait is invoked with no method error, but no error reported?",
-                                    );
-                            }
-                            Some(_) => unreachable!(),
-                            None => (),
-                        }
-                    }
-                    let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
-                    spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
-                    for (span, (_path, _self_ty, preds)) in spanned_predicates {
-                        let mut preds: Vec<_> = preds
-                            .into_iter()
-                            .filter_map(|pred| format_pred(*pred))
-                            .map(|(p, _)| format!("`{}`", p))
-                            .collect();
-                        preds.sort();
-                        preds.dedup();
-                        let msg = if let [pred] = &preds[..] {
-                            format!("trait bound {} was not satisfied", pred)
-                        } else {
-                            format!(
-                                "the following trait bounds were not satisfied:\n{}",
-                                preds.join("\n"),
-                            )
-                        };
-                        err.span_note(span, &msg);
-                        unsatisfied_bounds = true;
-                    }
-
-                    // The requirements that didn't have an `impl` span to show.
-                    let mut bound_list = unsatisfied_predicates
-                        .iter()
-                        .filter_map(|(pred, parent_pred, _cause)| {
-                            format_pred(*pred).map(|(p, self_ty)| {
-                                collect_type_param_suggestions(self_ty, *pred, &p);
-                                (
-                                    match parent_pred {
-                                        None => format!("`{}`", &p),
-                                        Some(parent_pred) => match format_pred(*parent_pred) {
-                                            None => format!("`{}`", &p),
-                                            Some((parent_p, _)) => {
-                                                collect_type_param_suggestions(
-                                                    self_ty,
-                                                    *parent_pred,
-                                                    &p,
-                                                );
-                                                format!(
-                                                    "`{}`\nwhich is required by `{}`",
-                                                    p, parent_p
-                                                )
-                                            }
-                                        },
-                                    },
-                                    *pred,
-                                )
-                            })
-                        })
-                        .filter(|(_, pred)| !skip_list.contains(&pred))
-                        .map(|(t, _)| t)
-                        .enumerate()
-                        .collect::<Vec<(usize, String)>>();
-
-                    for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
-                        restrict_type_params = true;
-                        // #74886: Sort here so that the output is always the same.
-                        let mut obligations = obligations.into_iter().collect::<Vec<_>>();
-                        obligations.sort();
-                        err.span_suggestion_verbose(
-                            span,
-                            &format!(
-                                "consider restricting the type parameter{s} to satisfy the \
-                                 trait bound{s}",
-                                s = pluralize!(obligations.len())
-                            ),
-                            format!("{} {}", add_where_or_comma, obligations.join(", ")),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-
-                    bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
-                    bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
-                    bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-
-                    if !bound_list.is_empty() || !skip_list.is_empty() {
-                        let bound_list = bound_list
-                            .into_iter()
-                            .map(|(_, path)| path)
-                            .collect::<Vec<_>>()
-                            .join("\n");
-                        let actual_prefix = rcvr_ty.prefix_string(self.tcx);
-                        info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
-                        let (primary_message, label) =
-                            if unimplemented_traits.len() == 1 && unimplemented_traits_only {
-                                unimplemented_traits
-                                    .into_iter()
-                                    .next()
-                                    .map(|(_, (trait_ref, obligation))| {
-                                        if trait_ref.self_ty().references_error()
-                                            || rcvr_ty.references_error()
-                                        {
-                                            // Avoid crashing.
-                                            return (None, None);
-                                        }
-                                        let OnUnimplementedNote { message, label, .. } = self
-                                            .err_ctxt()
-                                            .on_unimplemented_note(trait_ref, &obligation);
-                                        (message, label)
-                                    })
-                                    .unwrap()
-                            } else {
-                                (None, None)
-                            };
-                        let primary_message = primary_message.unwrap_or_else(|| format!(
-                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
-                             but its trait bounds were not satisfied"
-                        ));
-                        err.set_primary_message(&primary_message);
-                        if let Some(label) = label {
-                            custom_span_label = true;
-                            err.span_label(span, label);
-                        }
-                        if !bound_list.is_empty() {
-                            err.note(&format!(
-                                "the following trait bounds were not satisfied:\n{bound_list}"
-                            ));
-                        }
-                        self.suggest_derive(&mut err, &unsatisfied_predicates);
-
-                        unsatisfied_bounds = true;
-                    }
-                }
-
-                let label_span_not_found = |err: &mut Diagnostic| {
-                    if unsatisfied_predicates.is_empty() {
-                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
-                        let is_string_or_ref_str = match rcvr_ty.kind() {
-                            ty::Ref(_, ty, _) => {
-                                ty.is_str()
-                                    || matches!(
-                                        ty.kind(),
-                                        ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
-                                    )
-                            }
-                            ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
-                            _ => false,
-                        };
-                        if is_string_or_ref_str && item_name.name == sym::iter {
-                            err.span_suggestion_verbose(
-                                item_name.span,
-                                "because of the in-memory representation of `&str`, to obtain \
-                                 an `Iterator` over each of its codepoint use method `chars`",
-                                "chars",
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
-                            let mut inherent_impls_candidate = self
-                                .tcx
-                                .inherent_impls(adt.did())
-                                .iter()
-                                .copied()
-                                .filter(|def_id| {
-                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
-                                        // Check for both mode is the same so we avoid suggesting
-                                        // incorrect associated item.
-                                        match (mode, assoc.fn_has_self_parameter, source) {
-                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
-                                                // We check that the suggest type is actually
-                                                // different from the received one
-                                                // So we avoid suggestion method with Box<Self>
-                                                // for instance
-                                                self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                            }
-                                            (Mode::Path, false, _) => true,
-                                            _ => false,
-                                        }
-                                    } else {
-                                        false
-                                    }
-                                })
-                                .collect::<Vec<_>>();
-                            if !inherent_impls_candidate.is_empty() {
-                                inherent_impls_candidate.sort();
-                                inherent_impls_candidate.dedup();
-
-                                // number of type to shows at most.
-                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
-                                let type_candidates = inherent_impls_candidate
-                                    .iter()
-                                    .take(limit)
-                                    .map(|impl_item| {
-                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
-                                    })
-                                    .collect::<Vec<_>>()
-                                    .join("\n");
-                                let additional_types = if inherent_impls_candidate.len() > limit {
-                                    format!(
-                                        "\nand {} more types",
-                                        inherent_impls_candidate.len() - limit
-                                    )
-                                } else {
-                                    "".to_string()
-                                };
-                                err.note(&format!(
-                                    "the {item_kind} was found for\n{}{}",
-                                    type_candidates, additional_types
-                                ));
-                            }
-                        }
-                    } else {
-                        let ty_str = if ty_str.len() > 50 {
-                            String::new()
-                        } else {
-                            format!("on `{ty_str}` ")
-                        };
-                        err.span_label(span, format!(
-                            "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
-                        ));
-                    }
-                };
-
-                // If the method name is the name of a field with a function or closure type,
-                // give a helping note that it has to be called as `(x.f)(...)`.
-                if let SelfSource::MethodCall(expr) = source {
-                    if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
-                        && lev_candidate.is_none()
-                        && !custom_span_label
-                    {
-                        label_span_not_found(&mut err);
-                    }
-                } else if !custom_span_label {
-                    label_span_not_found(&mut err);
-                }
-
-                // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
-                // can't be called due to `typeof(expr): Clone` not holding.
-                if unsatisfied_predicates.is_empty() {
-                    self.suggest_calling_method_on_field(
-                        &mut err, source, span, rcvr_ty, item_name,
-                    );
-                }
-
-                self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
-
-                bound_spans.sort();
-                bound_spans.dedup();
-                for (span, msg) in bound_spans.into_iter() {
-                    err.span_label(span, &msg);
-                }
-
-                if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
-                } else {
-                    self.suggest_traits_to_import(
-                        &mut err,
-                        span,
-                        rcvr_ty,
-                        item_name,
-                        args.map(|(_, args)| args.len() + 1),
-                        source,
-                        out_of_scope_traits,
-                        &unsatisfied_predicates,
-                        &static_candidates,
-                        unsatisfied_bounds,
-                    );
-                }
-
-                // Don't emit a suggestion if we found an actual method
-                // that had unsatisfied trait bounds
-                if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
-                    let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
-                    if let Some(suggestion) = lev_distance::find_best_match_for_name(
-                        &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
-                        item_name.name,
-                        None,
-                    ) {
-                        err.span_suggestion(
-                            span,
-                            "there is a variant with a similar name",
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-
-                if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
-                    let msg = "remove this method call";
-                    let mut fallback_span = true;
-                    if let SelfSource::MethodCall(expr) = source {
-                        let call_expr =
-                            self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-                        if let Some(span) = call_expr.span.trim_start(expr.span) {
-                            err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
-                            fallback_span = false;
-                        }
-                    }
-                    if fallback_span {
-                        err.span_label(span, msg);
-                    }
-                } else if let Some(lev_candidate) = lev_candidate {
-                    // Don't emit a suggestion if we found an actual method
-                    // that had unsatisfied trait bounds
-                    if unsatisfied_predicates.is_empty() {
-                        let def_kind = lev_candidate.kind.as_def_kind();
-                        // Methods are defined within the context of a struct and their first parameter is always self,
-                        // which represents the instance of the struct the method is being called on
-                        // Associated functions don’t take self as a parameter and
-                        // they are not methods because they don’t have an instance of the struct to work with.
-                        if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
-                            err.span_suggestion(
-                                span,
-                                "there is a method with a similar name",
-                                lev_candidate.name,
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            err.span_suggestion(
-                                span,
-                                &format!(
-                                    "there is {} {} with a similar name",
-                                    def_kind.article(),
-                                    def_kind.descr(lev_candidate.def_id),
-                                ),
-                                lev_candidate.name,
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                }
-
-                self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
-
-                return Some(err);
             }
 
             MethodError::Ambiguity(mut sources) => {
@@ -1040,7 +143,15 @@ trait bound{s}",
                 );
                 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
 
-                report_candidates(span, &mut err, &mut sources, Some(sugg_span));
+                self.note_candidates_on_method_error(
+                    rcvr_ty,
+                    item_name,
+                    args,
+                    span,
+                    &mut err,
+                    &mut sources,
+                    Some(sugg_span),
+                );
                 err.emit();
             }
 
@@ -1065,10 +176,18 @@ trait bound{s}",
                 err.emit();
             }
 
-            MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
-                let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
+            MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
+                let msg = if needs_mut {
+                    with_forced_trimmed_paths!(format!(
+                        "the `{item_name}` method cannot be invoked on `{rcvr_ty}`"
+                    ))
+                } else {
+                    format!("the `{item_name}` method cannot be invoked on a trait object")
+                };
                 let mut err = self.sess().struct_span_err(span, &msg);
-                err.span_label(bound_span, "this has a `Sized` requirement");
+                if !needs_mut {
+                    err.span_label(bound_span, "this has a `Sized` requirement");
+                }
                 if !candidates.is_empty() {
                     let help = format!(
                         "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
@@ -1086,7 +205,32 @@ trait bound{s}",
                             *region,
                             ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
                         );
-                        err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
+                        let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
+                        let mut kind = &self_expr.kind;
+                        while let hir::ExprKind::AddrOf(_, _, expr)
+                        | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
+                        {
+                            kind = &expr.kind;
+                        }
+                        if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
+                            && let hir::def::Res::Local(hir_id) = path.res
+                            && let Some(hir::Node::Pat(b)) = self.tcx.hir().find(hir_id)
+                            && let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id)
+                            && let Some(node) = self.tcx.hir().find_parent(p.hir_id)
+                            && let Some(decl) = node.fn_decl()
+                            && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
+                            && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
+                            && let hir::Mutability::Not = mut_ty.mutbl
+                        {
+                            err.span_suggestion_verbose(
+                                mut_ty.ty.span.shrink_to_lo(),
+                                &msg,
+                                "mut ",
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            err.help(&msg);
+                        }
                     }
                 }
                 err.emit();
@@ -1097,6 +241,899 @@ trait bound{s}",
         None
     }
 
+    pub fn report_no_match_method_error(
+        &self,
+        mut span: Span,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        source: SelfSource<'tcx>,
+        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        sugg_span: Span,
+        no_match_data: &mut NoMatchData<'tcx>,
+    ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
+        let mode = no_match_data.mode;
+        let tcx = self.tcx;
+        let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
+        let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
+        let is_method = mode == Mode::MethodCall;
+        let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
+        let lev_candidate = no_match_data.lev_candidate;
+        let item_kind = if is_method {
+            "method"
+        } else if rcvr_ty.is_enum() {
+            "variant or associated item"
+        } else {
+            match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
+                (Some(name), false) if name.is_lowercase() => "function or associated item",
+                (Some(_), false) => "associated item",
+                (Some(_), true) | (None, false) => "variant or associated item",
+                (None, true) => "variant",
+            }
+        };
+
+        if self.suggest_wrapping_range_with_parens(tcx, rcvr_ty, source, span, item_name, &ty_str)
+            || self.suggest_constraining_numerical_ty(
+                tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
+            )
+        {
+            return None;
+        }
+        span = item_name.span;
+
+        // Don't show generic arguments when the method can't be found in any implementation (#81576).
+        let mut ty_str_reported = ty_str.clone();
+        if let ty::Adt(_, generics) = rcvr_ty.kind() {
+            if generics.len() > 0 {
+                let mut autoderef = self.autoderef(span, rcvr_ty);
+                let candidate_found = autoderef.any(|(ty, _)| {
+                    if let ty::Adt(adt_def, _) = ty.kind() {
+                        self.tcx
+                            .inherent_impls(adt_def.did())
+                            .iter()
+                            .any(|def_id| self.associated_value(*def_id, item_name).is_some())
+                    } else {
+                        false
+                    }
+                });
+                let has_deref = autoderef.step_count() > 0;
+                if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+                    if let Some((path_string, _)) = ty_str.split_once('<') {
+                        ty_str_reported = path_string.to_string();
+                    }
+                }
+            }
+        }
+
+        let mut err = struct_span_err!(
+            tcx.sess,
+            span,
+            E0599,
+            "no {} named `{}` found for {} `{}` in the current scope",
+            item_kind,
+            item_name,
+            rcvr_ty.prefix_string(self.tcx),
+            ty_str_reported,
+        );
+        if rcvr_ty.references_error() {
+            err.downgrade_to_delayed_bug();
+        }
+
+        if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+            self.suggest_await_before_method(
+                &mut err, item_name, rcvr_ty, cal, span,
+            );
+        }
+        if let Some(span) =
+            tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
+        {
+            err.span_suggestion(
+                span.shrink_to_lo(),
+                "you are looking for the module in `std`, not the primitive type",
+                "std::",
+                Applicability::MachineApplicable,
+            );
+        }
+        if let ty::RawPtr(_) = &rcvr_ty.kind() {
+            err.note(
+                "try using `<*const T>::as_ref()` to get a reference to the \
+                 type behind the pointer: https://doc.rust-lang.org/std/\
+                 primitive.pointer.html#method.as_ref",
+            );
+            err.note(
+                "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
+                 to invalid or uninitialized memory is undefined behavior",
+            );
+        }
+
+        let ty_span = match rcvr_ty.kind() {
+            ty::Param(param_type) => {
+                Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
+            }
+            ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
+            _ => None,
+        };
+        if let Some(span) = ty_span {
+            err.span_label(
+                span,
+                format!(
+                    "{item_kind} `{item_name}` not found for this {}",
+                    rcvr_ty.prefix_string(self.tcx)
+                ),
+            );
+        }
+
+        if let SelfSource::MethodCall(rcvr_expr) = source {
+            self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
+                let call_expr =
+                    self.tcx.hir().expect_expr(self.tcx.hir().parent_id(rcvr_expr.hir_id));
+                let probe =
+                    self.lookup_probe(item_name, output_ty, call_expr, ProbeScope::AllTraits);
+                probe.is_ok()
+            });
+        }
+
+        let mut custom_span_label = false;
+
+        let static_candidates = &mut no_match_data.static_candidates;
+        if !static_candidates.is_empty() {
+            err.note(
+                "found the following associated functions; to be used as methods, \
+                 functions must have a `self` parameter",
+            );
+            err.span_label(span, "this is an associated function, not a method");
+            custom_span_label = true;
+        }
+        if static_candidates.len() == 1 {
+            self.suggest_associated_call_syntax(
+                &mut err,
+                &static_candidates,
+                rcvr_ty,
+                source,
+                item_name,
+                args,
+                sugg_span,
+            );
+
+            self.note_candidates_on_method_error(
+                rcvr_ty,
+                item_name,
+                args,
+                span,
+                &mut err,
+                static_candidates,
+                None,
+            );
+        } else if static_candidates.len() > 1 {
+            self.note_candidates_on_method_error(
+                rcvr_ty,
+                item_name,
+                args,
+                span,
+                &mut err,
+                static_candidates,
+                Some(sugg_span),
+            );
+        }
+
+        let mut bound_spans = vec![];
+        let mut restrict_type_params = false;
+        let mut unsatisfied_bounds = false;
+        if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
+            let msg = "consider using `len` instead";
+            if let SelfSource::MethodCall(_expr) = source {
+                err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
+            } else {
+                err.span_label(span, msg);
+            }
+            if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
+                let iterator_trait = self.tcx.def_path_str(iterator_trait);
+                err.note(&format!(
+                    "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
+                ));
+            }
+        } else if !unsatisfied_predicates.is_empty() {
+            let mut type_params = FxHashMap::default();
+
+            // Pick out the list of unimplemented traits on the receiver.
+            // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+            let mut unimplemented_traits = FxHashMap::default();
+            let mut unimplemented_traits_only = true;
+            for (predicate, _parent_pred, cause) in unsatisfied_predicates {
+                if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
+                    (predicate.kind().skip_binder(), cause.as_ref())
+                {
+                    if p.trait_ref.self_ty() != rcvr_ty {
+                        // This is necessary, not just to keep the errors clean, but also
+                        // because our derived obligations can wind up with a trait ref that
+                        // requires a different param_env to be correctly compared.
+                        continue;
+                    }
+                    unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+                        predicate.kind().rebind(p.trait_ref),
+                        Obligation {
+                            cause: cause.clone(),
+                            param_env: self.param_env,
+                            predicate: *predicate,
+                            recursion_depth: 0,
+                        },
+                    ));
+                }
+            }
+
+            // Make sure that, if any traits other than the found ones were involved,
+            // we don't don't report an unimplemented trait.
+            // We don't want to say that `iter::Cloned` is not an iterator, just
+            // because of some non-Clone item being iterated over.
+            for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
+                match predicate.kind().skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Trait(p))
+                        if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
+                    _ => {
+                        unimplemented_traits_only = false;
+                        break;
+                    }
+                }
+            }
+
+            let mut collect_type_param_suggestions =
+                |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
+                    // We don't care about regions here, so it's fine to skip the binder here.
+                    if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
+                        (self_ty.kind(), parent_pred.kind().skip_binder())
+                    {
+                        let hir = self.tcx.hir();
+                        let node = match p.trait_ref.self_ty().kind() {
+                            ty::Param(_) => {
+                                // Account for `fn` items like in `issue-35677.rs` to
+                                // suggest restricting its type params.
+                                let parent_body =
+                                    hir.body_owner(hir::BodyId { hir_id: self.body_id });
+                                Some(hir.get(parent_body))
+                            }
+                            ty::Adt(def, _) => {
+                                def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
+                            }
+                            _ => None,
+                        };
+                        if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+                            if let Some(g) = kind.generics() {
+                                let key = (
+                                    g.tail_span_for_predicate_suggestion(),
+                                    g.add_where_or_trailing_comma(),
+                                );
+                                type_params
+                                    .entry(key)
+                                    .or_insert_with(FxHashSet::default)
+                                    .insert(obligation.to_owned());
+                            }
+                        }
+                    }
+                };
+            let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
+                let msg = format!(
+                    "doesn't satisfy `{}`",
+                    if obligation.len() > 50 { quiet } else { obligation }
+                );
+                match &self_ty.kind() {
+                    // Point at the type that couldn't satisfy the bound.
+                    ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
+                    // Point at the trait object that couldn't satisfy the bound.
+                    ty::Dynamic(preds, _, _) => {
+                        for pred in preds.iter() {
+                            match pred.skip_binder() {
+                                ty::ExistentialPredicate::Trait(tr) => {
+                                    bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
+                                }
+                                ty::ExistentialPredicate::Projection(_)
+                                | ty::ExistentialPredicate::AutoTrait(_) => {}
+                            }
+                        }
+                    }
+                    // Point at the closure that couldn't satisfy the bound.
+                    ty::Closure(def_id, _) => bound_spans
+                        .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
+                    _ => {}
+                }
+            };
+            let mut format_pred = |pred: ty::Predicate<'tcx>| {
+                let bound_predicate = pred.kind();
+                match bound_predicate.skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+                        let pred = bound_predicate.rebind(pred);
+                        // `<Foo as Iterator>::Item = String`.
+                        let projection_ty = pred.skip_binder().projection_ty;
+
+                        let substs_with_infer_self = tcx.mk_substs(
+                            iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+                                .chain(projection_ty.substs.iter().skip(1)),
+                        );
+
+                        let quiet_projection_ty =
+                            tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
+
+                        let term = pred.skip_binder().term;
+
+                        let obligation = format!("{} = {}", projection_ty, term);
+                        let quiet = with_forced_trimmed_paths!(format!(
+                            "{} = {}",
+                            quiet_projection_ty, term
+                        ));
+
+                        bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                        Some((obligation, projection_ty.self_ty()))
+                    }
+                    ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
+                        let p = poly_trait_ref.trait_ref;
+                        let self_ty = p.self_ty();
+                        let path = p.print_only_trait_path();
+                        let obligation = format!("{}: {}", self_ty, path);
+                        let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
+                        bound_span_label(self_ty, &obligation, &quiet);
+                        Some((obligation, self_ty))
+                    }
+                    _ => None,
+                }
+            };
+
+            // Find all the requirements that come from a local `impl` block.
+            let mut skip_list: FxHashSet<_> = Default::default();
+            let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+            for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
+                .iter()
+                .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+                .filter_map(|(p, parent, c)| match c.code() {
+                    ObligationCauseCode::ImplDerivedObligation(data) => {
+                        Some((&data.derived, p, parent, data.impl_def_id, data))
+                    }
+                    _ => None,
+                })
+            {
+                let parent_trait_ref = data.parent_trait_pred;
+                let path = parent_trait_ref.print_modifiers_and_trait_path();
+                let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+                let unsatisfied_msg = "unsatisfied trait bound introduced here";
+                let derive_msg = "unsatisfied trait bound introduced in this `derive` macro";
+                match self.tcx.hir().get_if_local(impl_def_id) {
+                    // Unmet obligation comes from a `derive` macro, point at it once to
+                    // avoid multiple span labels pointing at the same place.
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                        ..
+                    })) if matches!(
+                        self_ty.span.ctxt().outer_expn_data().kind,
+                        ExpnKind::Macro(MacroKind::Derive, _)
+                    ) || matches!(
+                        of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
+                        Some(ExpnKind::Macro(MacroKind::Derive, _))
+                    ) =>
+                    {
+                        let span = self_ty.span.ctxt().outer_expn_data().call_site;
+                        let mut spans: MultiSpan = span.into();
+                        spans.push_span_label(span, derive_msg);
+                        let entry = spanned_predicates.entry(spans);
+                        entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                    }
+
+                    // Unmet obligation coming from an `impl`.
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
+                        span: item_span,
+                        ..
+                    })) => {
+                        let sized_pred =
+                            unsatisfied_predicates.iter().any(|(pred, _, _)| {
+                                match pred.kind().skip_binder() {
+                                    ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
+                                        Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
+                                            && pred.polarity == ty::ImplPolarity::Positive
+                                    }
+                                    _ => false,
+                                }
+                            });
+                        for param in generics.params {
+                            if param.span == cause.span && sized_pred {
+                                let (sp, sugg) = match param.colon_span {
+                                    Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
+                                    None => (param.span.shrink_to_hi(), ": ?Sized"),
+                                };
+                                err.span_suggestion_verbose(
+                                    sp,
+                                    "consider relaxing the type parameter's implicit \
+                                     `Sized` bound",
+                                    sugg,
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
+                        if let Some(pred) = parent_p {
+                            // Done to add the "doesn't satisfy" `span_label`.
+                            let _ = format_pred(*pred);
+                        }
+                        skip_list.insert(p);
+                        let mut spans = if cause.span != *item_span {
+                            let mut spans: MultiSpan = cause.span.into();
+                            spans.push_span_label(cause.span, unsatisfied_msg);
+                            spans
+                        } else {
+                            let mut spans = Vec::with_capacity(2);
+                            if let Some(trait_ref) = of_trait {
+                                spans.push(trait_ref.path.span);
+                            }
+                            spans.push(self_ty.span);
+                            spans.into()
+                        };
+                        if let Some(trait_ref) = of_trait {
+                            spans.push_span_label(trait_ref.path.span, "");
+                        }
+                        spans.push_span_label(self_ty.span, "");
+
+                        let entry = spanned_predicates.entry(spans);
+                        entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                    }
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+                        span: item_span,
+                        ..
+                    })) => {
+                        tcx.sess.delay_span_bug(
+                            *item_span,
+                            "auto trait is invoked with no method error, but no error reported?",
+                        );
+                    }
+                    Some(_) => unreachable!(),
+                    None => (),
+                }
+            }
+            let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
+            spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
+            for (span, (_path, _self_ty, preds)) in spanned_predicates {
+                let mut preds: Vec<_> = preds
+                    .into_iter()
+                    .filter_map(|pred| format_pred(*pred))
+                    .map(|(p, _)| format!("`{}`", p))
+                    .collect();
+                preds.sort();
+                preds.dedup();
+                let msg = if let [pred] = &preds[..] {
+                    format!("trait bound {} was not satisfied", pred)
+                } else {
+                    format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
+                };
+                err.span_note(span, &msg);
+                unsatisfied_bounds = true;
+            }
+
+            // The requirements that didn't have an `impl` span to show.
+            let mut bound_list = unsatisfied_predicates
+                .iter()
+                .filter_map(|(pred, parent_pred, _cause)| {
+                    format_pred(*pred).map(|(p, self_ty)| {
+                        collect_type_param_suggestions(self_ty, *pred, &p);
+                        (
+                            match parent_pred {
+                                None => format!("`{}`", &p),
+                                Some(parent_pred) => match format_pred(*parent_pred) {
+                                    None => format!("`{}`", &p),
+                                    Some((parent_p, _)) => {
+                                        collect_type_param_suggestions(self_ty, *parent_pred, &p);
+                                        format!("`{}`\nwhich is required by `{}`", p, parent_p)
+                                    }
+                                },
+                            },
+                            *pred,
+                        )
+                    })
+                })
+                .filter(|(_, pred)| !skip_list.contains(&pred))
+                .map(|(t, _)| t)
+                .enumerate()
+                .collect::<Vec<(usize, String)>>();
+
+            for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+                restrict_type_params = true;
+                // #74886: Sort here so that the output is always the same.
+                let mut obligations = obligations.into_iter().collect::<Vec<_>>();
+                obligations.sort();
+                err.span_suggestion_verbose(
+                    span,
+                    &format!(
+                        "consider restricting the type parameter{s} to satisfy the \
+                         trait bound{s}",
+                        s = pluralize!(obligations.len())
+                    ),
+                    format!("{} {}", add_where_or_comma, obligations.join(", ")),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
+            bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
+            bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
+
+            if !bound_list.is_empty() || !skip_list.is_empty() {
+                let bound_list =
+                    bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
+                let actual_prefix = rcvr_ty.prefix_string(self.tcx);
+                info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+                let (primary_message, label) = if unimplemented_traits.len() == 1
+                    && unimplemented_traits_only
+                {
+                    unimplemented_traits
+                        .into_iter()
+                        .next()
+                        .map(|(_, (trait_ref, obligation))| {
+                            if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
+                            {
+                                // Avoid crashing.
+                                return (None, None);
+                            }
+                            let OnUnimplementedNote { message, label, .. } =
+                                self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
+                            (message, label)
+                        })
+                        .unwrap()
+                } else {
+                    (None, None)
+                };
+                let primary_message = primary_message.unwrap_or_else(|| {
+                    format!(
+                        "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+                    but its trait bounds were not satisfied"
+                    )
+                });
+                err.set_primary_message(&primary_message);
+                if let Some(label) = label {
+                    custom_span_label = true;
+                    err.span_label(span, label);
+                }
+                if !bound_list.is_empty() {
+                    err.note(&format!(
+                        "the following trait bounds were not satisfied:\n{bound_list}"
+                    ));
+                }
+                self.suggest_derive(&mut err, &unsatisfied_predicates);
+
+                unsatisfied_bounds = true;
+            }
+        }
+
+        let label_span_not_found = |err: &mut Diagnostic| {
+            if unsatisfied_predicates.is_empty() {
+                err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                let is_string_or_ref_str = match rcvr_ty.kind() {
+                    ty::Ref(_, ty, _) => {
+                        ty.is_str()
+                            || matches!(
+                                ty.kind(),
+                                ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
+                            )
+                    }
+                    ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
+                    _ => false,
+                };
+                if is_string_or_ref_str && item_name.name == sym::iter {
+                    err.span_suggestion_verbose(
+                        item_name.span,
+                        "because of the in-memory representation of `&str`, to obtain \
+                         an `Iterator` over each of its codepoint use method `chars`",
+                        "chars",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                if let ty::Adt(adt, _) = rcvr_ty.kind() {
+                    let mut inherent_impls_candidate = self
+                        .tcx
+                        .inherent_impls(adt.did())
+                        .iter()
+                        .copied()
+                        .filter(|def_id| {
+                            if let Some(assoc) = self.associated_value(*def_id, item_name) {
+                                // Check for both mode is the same so we avoid suggesting
+                                // incorrect associated item.
+                                match (mode, assoc.fn_has_self_parameter, source) {
+                                    (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                        // We check that the suggest type is actually
+                                        // different from the received one
+                                        // So we avoid suggestion method with Box<Self>
+                                        // for instance
+                                        self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                    }
+                                    (Mode::Path, false, _) => true,
+                                    _ => false,
+                                }
+                            } else {
+                                false
+                            }
+                        })
+                        .collect::<Vec<_>>();
+                    if !inherent_impls_candidate.is_empty() {
+                        inherent_impls_candidate.sort();
+                        inherent_impls_candidate.dedup();
+
+                        // number of type to shows at most.
+                        let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                        let type_candidates = inherent_impls_candidate
+                            .iter()
+                            .take(limit)
+                            .map(|impl_item| {
+                                format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                            })
+                            .collect::<Vec<_>>()
+                            .join("\n");
+                        let additional_types = if inherent_impls_candidate.len() > limit {
+                            format!("\nand {} more types", inherent_impls_candidate.len() - limit)
+                        } else {
+                            "".to_string()
+                        };
+                        err.note(&format!(
+                            "the {item_kind} was found for\n{}{}",
+                            type_candidates, additional_types
+                        ));
+                    }
+                }
+            } else {
+                let ty_str =
+                    if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
+                err.span_label(
+                    span,
+                    format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
+                );
+            }
+        };
+
+        // If the method name is the name of a field with a function or closure type,
+        // give a helping note that it has to be called as `(x.f)(...)`.
+        if let SelfSource::MethodCall(expr) = source {
+            if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
+                && lev_candidate.is_none()
+                && !custom_span_label
+            {
+                label_span_not_found(&mut err);
+            }
+        } else if !custom_span_label {
+            label_span_not_found(&mut err);
+        }
+
+        // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
+        // can't be called due to `typeof(expr): Clone` not holding.
+        if unsatisfied_predicates.is_empty() {
+            self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
+        }
+
+        self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+
+        bound_spans.sort();
+        bound_spans.dedup();
+        for (span, msg) in bound_spans.into_iter() {
+            err.span_label(span, &msg);
+        }
+
+        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
+        } else {
+            self.suggest_traits_to_import(
+                &mut err,
+                span,
+                rcvr_ty,
+                item_name,
+                args.map(|(_, args)| args.len() + 1),
+                source,
+                no_match_data.out_of_scope_traits.clone(),
+                &unsatisfied_predicates,
+                &static_candidates,
+                unsatisfied_bounds,
+            );
+        }
+
+        // Don't emit a suggestion if we found an actual method
+        // that had unsatisfied trait bounds
+        if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
+            let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
+            if let Some(suggestion) = lev_distance::find_best_match_for_name(
+                &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
+                item_name.name,
+                None,
+            ) {
+                err.span_suggestion(
+                    span,
+                    "there is a variant with a similar name",
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+
+        if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
+            let msg = "remove this method call";
+            let mut fallback_span = true;
+            if let SelfSource::MethodCall(expr) = source {
+                let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
+                if let Some(span) = call_expr.span.trim_start(expr.span) {
+                    err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
+                    fallback_span = false;
+                }
+            }
+            if fallback_span {
+                err.span_label(span, msg);
+            }
+        } else if let Some(lev_candidate) = lev_candidate {
+            // Don't emit a suggestion if we found an actual method
+            // that had unsatisfied trait bounds
+            if unsatisfied_predicates.is_empty() {
+                let def_kind = lev_candidate.kind.as_def_kind();
+                // Methods are defined within the context of a struct and their first parameter is always self,
+                // which represents the instance of the struct the method is being called on
+                // Associated functions don’t take self as a parameter and
+                // they are not methods because they don’t have an instance of the struct to work with.
+                if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
+                    err.span_suggestion(
+                        span,
+                        "there is a method with a similar name",
+                        lev_candidate.name,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_suggestion(
+                        span,
+                        &format!(
+                            "there is {} {} with a similar name",
+                            def_kind.article(),
+                            def_kind.descr(lev_candidate.def_id),
+                        ),
+                        lev_candidate.name,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+
+        self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+        return Some(err);
+    }
+
+    fn note_candidates_on_method_error(
+        &self,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        span: Span,
+        err: &mut Diagnostic,
+        sources: &mut Vec<CandidateSource>,
+        sugg_span: Option<Span>,
+    ) {
+        sources.sort();
+        sources.dedup();
+        // Dynamic limit to avoid hiding just one candidate, which is silly.
+        let limit = if sources.len() == 5 { 5 } else { 4 };
+
+        for (idx, source) in sources.iter().take(limit).enumerate() {
+            match *source {
+                CandidateSource::Impl(impl_did) => {
+                    // Provide the best span we can. Use the item, if local to crate, else
+                    // the impl, if local to crate (item may be defaulted), else nothing.
+                    let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
+                        let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+                        self.associated_value(impl_trait_ref.def_id, item_name)
+                    }) else {
+                        continue;
+                    };
+
+                    let note_span = if item.def_id.is_local() {
+                        Some(self.tcx.def_span(item.def_id))
+                    } else if impl_did.is_local() {
+                        Some(self.tcx.def_span(impl_did))
+                    } else {
+                        None
+                    };
+
+                    let impl_ty = self.tcx.at(span).type_of(impl_did);
+
+                    let insertion = match self.tcx.impl_trait_ref(impl_did) {
+                        None => String::new(),
+                        Some(trait_ref) => {
+                            format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
+                        }
+                    };
+
+                    let (note_str, idx) = if sources.len() > 1 {
+                        (
+                            format!(
+                                "candidate #{} is defined in an impl{} for the type `{}`",
+                                idx + 1,
+                                insertion,
+                                impl_ty,
+                            ),
+                            Some(idx + 1),
+                        )
+                    } else {
+                        (
+                            format!(
+                                "the candidate is defined in an impl{} for the type `{}`",
+                                insertion, impl_ty,
+                            ),
+                            None,
+                        )
+                    };
+                    if let Some(note_span) = note_span {
+                        // We have a span pointing to the method. Show note with snippet.
+                        err.span_note(note_span, &note_str);
+                    } else {
+                        err.note(&note_str);
+                    }
+                    if let Some(sugg_span) = sugg_span
+                        && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
+                        let path = self.tcx.def_path_str(trait_ref.def_id);
+
+                        let ty = match item.kind {
+                            ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
+                            ty::AssocKind::Fn => self
+                                .tcx
+                                .fn_sig(item.def_id)
+                                .inputs()
+                                .skip_binder()
+                                .get(0)
+                                .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+                                .copied()
+                                .unwrap_or(rcvr_ty),
+                        };
+                        print_disambiguation_help(
+                            item_name,
+                            args,
+                            err,
+                            path,
+                            ty,
+                            item.kind,
+                            item.def_id,
+                            sugg_span,
+                            idx,
+                            self.tcx.sess.source_map(),
+                            item.fn_has_self_parameter,
+                        );
+                    }
+                }
+                CandidateSource::Trait(trait_did) => {
+                    let Some(item) = self.associated_value(trait_did, item_name) else { continue };
+                    let item_span = self.tcx.def_span(item.def_id);
+                    let idx = if sources.len() > 1 {
+                        let msg = &format!(
+                            "candidate #{} is defined in the trait `{}`",
+                            idx + 1,
+                            self.tcx.def_path_str(trait_did)
+                        );
+                        err.span_note(item_span, msg);
+                        Some(idx + 1)
+                    } else {
+                        let msg = &format!(
+                            "the candidate is defined in the trait `{}`",
+                            self.tcx.def_path_str(trait_did)
+                        );
+                        err.span_note(item_span, msg);
+                        None
+                    };
+                    if let Some(sugg_span) = sugg_span {
+                        let path = self.tcx.def_path_str(trait_did);
+                        print_disambiguation_help(
+                            item_name,
+                            args,
+                            err,
+                            path,
+                            rcvr_ty,
+                            item.kind,
+                            item.def_id,
+                            sugg_span,
+                            idx,
+                            self.tcx.sess.source_map(),
+                            item.fn_has_self_parameter,
+                        );
+                    }
+                }
+            }
+        }
+        if sources.len() > limit {
+            err.note(&format!("and {} others", sources.len() - limit));
+        }
+    }
+
     /// Suggest calling `Ty::method` if `.method()` isn't found because the method
     /// doesn't take a `self` receiver.
     fn suggest_associated_call_syntax(
@@ -1263,7 +1300,7 @@ fn suggest_calling_field_as_fn(
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+                    let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
 
                     if let Some(span) = call_expr.span.trim_start(item_name.span) {
                         err.span_suggestion(
@@ -1445,7 +1482,7 @@ fn suggest_constraining_numerical_ty(
                         let filename = tcx.sess.source_map().span_to_filename(span);
 
                         let parent_node =
-                            self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
+                            self.tcx.hir().get_parent(hir_id);
                         let msg = format!(
                             "you must specify a type for this binding, like `{}`",
                             concrete_type,
@@ -1518,7 +1555,7 @@ fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
         let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
         visitor.visit_body(&body);
 
-        let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
+        let parent = self.tcx.hir().parent_id(seg1.hir_id);
         if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
             && let Some(expr) = visitor.result
             && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
@@ -1556,7 +1593,7 @@ fn suggest_calling_method_on_field(
         && let Some((fields, substs)) =
             self.get_field_candidates_considering_privacy(span, actual, mod_id)
         {
-            let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+            let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
 
             let lang_items = self.tcx.lang_items();
             let never_mention_traits = [
@@ -1626,7 +1663,7 @@ fn check_for_inner_self(
     ) {
         let tcx = self.tcx;
         let SelfSource::MethodCall(expr) = source else { return; };
-        let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+        let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
 
         let ty::Adt(kind, substs) = actual.kind() else { return; };
         match kind.adt_kind() {
@@ -2306,6 +2343,7 @@ fn suggest_traits_to_import(
                         _ => false,
                     }
                 }) && (type_is_local || info.def_id.is_local())
+                    && !self.tcx.trait_is_auto(info.def_id)
                     && self
                         .associated_value(info.def_id, item_name)
                         .filter(|item| {
@@ -2586,7 +2624,7 @@ pub(crate) fn suggest_else_fn_with_closure(
             return false;
         }
 
-        let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+        let parent = self.tcx.hir().parent_id(expr.hir_id);
         if  let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
             let hir::ExprKind::MethodCall(
                 hir::PathSegment { ident: method_name, .. },
index 9f0d175c4c669870d4edff2499bb79f2490ddb3d..78cea1f4d8d3e199295d83834e2e33398b5d2851 100644 (file)
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
-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_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::FulfillmentError;
+use rustc_trait_selection::traits::{self, FulfillmentError};
 use rustc_type_ir::sty::TyKind::*;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -48,8 +50,7 @@ pub fn check_binop_assign(
                 if self
                     .lookup_op_method(
                         lhs_deref_ty,
-                        Some(rhs_ty),
-                        Some(rhs),
+                        Some((rhs, rhs_ty)),
                         Op::Binary(op, IsAssign::Yes),
                         expected,
                     )
@@ -60,8 +61,7 @@ pub fn check_binop_assign(
                     if self
                         .lookup_op_method(
                             lhs_ty,
-                            Some(rhs_ty),
-                            Some(rhs),
+                            Some((rhs, rhs_ty)),
                             Op::Binary(op, IsAssign::Yes),
                             expected,
                         )
@@ -248,8 +248,7 @@ fn check_overloaded_binop(
 
         let result = self.lookup_op_method(
             lhs_ty,
-            Some(rhs_ty_var),
-            Some(rhs_expr),
+            Some((rhs_expr, rhs_ty_var)),
             Op::Binary(op, is_assign),
             expected,
         );
@@ -382,8 +381,7 @@ fn check_overloaded_binop(
                     if self
                         .lookup_op_method(
                             lhs_deref_ty,
-                            Some(rhs_ty),
-                            Some(rhs_expr),
+                            Some((rhs_expr, rhs_ty)),
                             Op::Binary(op, is_assign),
                             expected,
                         )
@@ -410,8 +408,7 @@ fn check_overloaded_binop(
                 let is_compatible = |lhs_ty, rhs_ty| {
                     self.lookup_op_method(
                         lhs_ty,
-                        Some(rhs_ty),
-                        Some(rhs_expr),
+                        Some((rhs_expr, rhs_ty)),
                         Op::Binary(op, is_assign),
                         expected,
                     )
@@ -471,8 +468,7 @@ fn check_overloaded_binop(
                         let errors = self
                             .lookup_op_method(
                                 lhs_ty,
-                                Some(rhs_ty),
-                                Some(rhs_expr),
+                                Some((rhs_expr, rhs_ty)),
                                 Op::Binary(op, is_assign),
                                 expected,
                             )
@@ -492,6 +488,7 @@ 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)
                                             {
                                                 Some(("Output", *output_ty))
                                             } else {
@@ -625,7 +622,7 @@ pub fn check_user_unop(
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         assert!(op.is_by_value());
-        match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) {
+        match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) {
             Ok(method) => {
                 self.write_method_call(ex.hir_id, method);
                 method.sig.output()
@@ -660,7 +657,7 @@ pub fn check_user_unop(
                         }
                     }
 
-                    let sp = self.tcx.sess.source_map().start_point(ex.span);
+                    let sp = self.tcx.sess.source_map().start_point(ex.span).with_parent(None);
                     if let Some(sp) =
                         self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
                     {
@@ -712,8 +709,7 @@ pub fn check_user_unop(
     fn lookup_op_method(
         &self,
         lhs_ty: Ty<'tcx>,
-        other_ty: Option<Ty<'tcx>>,
-        other_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+        opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>,
         op: Op,
         expected: Expectation<'tcx>,
     ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
@@ -742,20 +738,27 @@ fn lookup_op_method(
                 Op::Unary(..) => 0,
             },
         ) {
+            self.tcx
+                .sess
+                .delay_span_bug(span, "operator didn't have the right number of generic args");
             return Err(vec![]);
         }
 
         let opname = Ident::with_dummy_span(opname);
+        let input_types =
+            opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default();
+        let cause = self.cause(
+            span,
+            traits::BinOp {
+                rhs_span: opt_rhs.map(|(expr, _)| expr.span),
+                is_lit: opt_rhs
+                    .map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))),
+                output_ty: expected.only_has_type(self),
+            },
+        );
+
         let method = trait_did.and_then(|trait_did| {
-            self.lookup_op_method_in_trait(
-                span,
-                opname,
-                trait_did,
-                lhs_ty,
-                other_ty,
-                other_ty_expr,
-                expected,
-            )
+            self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
         });
 
         match (method, trait_did) {
@@ -766,14 +769,8 @@ fn lookup_op_method(
             }
             (None, None) => Err(vec![]),
             (None, Some(trait_did)) => {
-                let (obligation, _) = self.obligation_for_op_method(
-                    span,
-                    trait_did,
-                    lhs_ty,
-                    other_ty,
-                    other_ty_expr,
-                    expected,
-                );
+                let (obligation, _) =
+                    self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
                 Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
             }
         }
index 0021fdd7f61a9f9200aa7e8cb29a536b97a16f2e..46799245222dc45599c6fbcbb71f9c9040109b15 100644 (file)
@@ -1,4 +1,4 @@
-use crate::FnCtxt;
+use crate::{FnCtxt, RawTy};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
@@ -553,6 +553,9 @@ fn emit_err_pat_range(
             (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
             _ => span_bug!(span, "Impossible, verified above."),
         }
+        if (lhs, rhs).references_error() {
+            err.downgrade_to_delayed_bug();
+        }
         if self.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "In a match expression, only numbers and characters can be matched \
@@ -692,7 +695,7 @@ fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
         let tcx = self.tcx;
         if let PatKind::Ref(inner, mutbl) = pat.kind
         && let PatKind::Binding(_, _, binding, ..) = inner.kind {
-            let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id);
+            let binding_parent_id = tcx.hir().parent_id(pat.hir_id);
             let binding_parent = tcx.hir().get(binding_parent_id);
             debug!(?inner, ?pat, ?binding_parent);
 
@@ -758,6 +761,23 @@ fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
                         err.span_note(sp, format!("{msg}: `{sugg}`"));
                     }
                 }
+                hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
+                    for i in pat_arr.iter() {
+                        if let PatKind::Ref(the_ref, _) = i.kind
+                        && let PatKind::Binding(mt, _, ident, _) = the_ref.kind {
+                            let hir::BindingAnnotation(_, mtblty) = mt;
+                            err.span_suggestion_verbose(
+                                i.span,
+                                format!("consider removing `&{mutability}` from the pattern"),
+                                mtblty.prefix_str().to_string() + &ident.name.to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                    if let Some((sp, msg, sugg)) = mut_var_suggestion {
+                        err.span_note(sp, format!("{msg}: `{sugg}`"));
+                    }
+                }
                 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
                     // rely on match ergonomics or it might be nested `&&pat`
                     err.span_suggestion_verbose(
@@ -839,7 +859,7 @@ fn check_pat_path(
         &self,
         pat: &Pat<'tcx>,
         qpath: &hir::QPath<'_>,
-        path_resolution: (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
+        path_resolution: (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
         expected: Ty<'tcx>,
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
@@ -936,7 +956,7 @@ fn emit_bad_pat_path(
                         res.descr(),
                     ),
                 );
-                match self.tcx.hir().get(self.tcx.hir().get_parent_node(pat.hir_id)) {
+                match self.tcx.hir().get_parent(pat.hir_id) {
                     hir::Node::PatField(..) => {
                         e.span_suggestion_verbose(
                             ident.span.shrink_to_hi(),
@@ -1921,7 +1941,7 @@ fn check_pat_ref(
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let expected = self.shallow_resolve(expected);
-        let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) {
+        let (ref_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) {
             // `demand::subtype` would be good enough, but using `eqtype` turns
             // out to be equally general. See (note_1) for details.
 
@@ -1936,9 +1956,9 @@ fn check_pat_ref(
                         kind: TypeVariableOriginKind::TypeInference,
                         span: inner.span,
                     });
-                    let rptr_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
-                    debug!("check_pat_ref: demanding {:?} = {:?}", expected, rptr_ty);
-                    let err = self.demand_eqtype_pat_diag(pat.span, expected, rptr_ty, ti);
+                    let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
+                    debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+                    let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti);
 
                     // Look for a case like `fn foo(&foo: u32)` and suggest
                     // `fn foo(foo: &u32)`
@@ -1946,7 +1966,7 @@ fn check_pat_ref(
                         self.borrow_pat_suggestion(&mut err, pat);
                         err.emit();
                     }
-                    (rptr_ty, inner_ty)
+                    (ref_ty, inner_ty)
                 }
             }
         } else {
@@ -1954,7 +1974,7 @@ fn check_pat_ref(
             (err, err)
         };
         self.check_pat(inner, inner_ty, def_bm, ti);
-        rptr_ty
+        ref_ty
     }
 
     /// Create a reference type with a fresh region variable.
index 952ea14887f7bc7f279de7c1863e523c61c0195a..a0f048fc09b9b017101fb4f59f7602f2ec4bd09d 100644 (file)
@@ -225,7 +225,7 @@ pub(super) fn try_overloaded_place_op(
 
         imm_tr.and_then(|trait_did| {
             self.lookup_method_in_trait(
-                span,
+                self.misc(span),
                 Ident::with_dummy_span(imm_op),
                 trait_did,
                 base_ty,
@@ -264,7 +264,7 @@ fn try_mutable_overloaded_place_op(
 
         mut_tr.and_then(|trait_did| {
             self.lookup_method_in_trait(
-                span,
+                self.misc(span),
                 Ident::with_dummy_span(mut_op),
                 trait_did,
                 base_ty,
index 686cb6dac496224f130d3f08a2f17d685eb30a32..15179392c88cdb9166d901fa67b180bb19acec64 100644 (file)
@@ -1091,7 +1091,7 @@ fn to_string(&self) -> String {
                 assert!(mask <= 0xFF);
                 let byte = word & mask;
 
-                result.push_str(&format!("{}{:02x}", sep, byte));
+                result.push_str(&format!("{sep}{byte:02x}"));
 
                 if remain <= 8 {
                     break;
index 3592fb33077d92ed33e392c75bbc88ec117f419b..d809740c6ab31f8f332fc1689931bd3652dcd338 100644 (file)
@@ -135,10 +135,7 @@ pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
         };
         debug_assert!(
             self.check_invariants(),
-            "wrong intervals after insert {:?}..={:?} to {:?}",
-            start,
-            end,
-            self
+            "wrong intervals after insert {start:?}..={end:?} to {self:?}"
         );
         result
     }
index c4f11472d55482e979acfdb41894115a7a6a4923..033a1842edb25c57c95ea20d97c910be67a82c3e 100644 (file)
@@ -1,15 +1,18 @@
 use hir::GenericParamKind;
 use rustc_errors::{
     fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
-    MultiSpan, SubdiagnosticMessage,
+    IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage,
 };
 use rustc_hir as hir;
-use rustc_hir::{FnRetTy, Ty};
+use rustc_hir::FnRetTy;
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::{Region, TyCtxt};
+use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
+use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt};
 use rustc_span::symbol::kw;
+use rustc_span::Symbol;
 use rustc_span::{symbol::Ident, BytePos, Span};
 
+use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted;
 use crate::infer::error_reporting::{
     need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
     ObligationCauseAsDiagArg,
@@ -357,8 +360,8 @@ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
 pub struct AddLifetimeParamsSuggestion<'a> {
     pub tcx: TyCtxt<'a>,
     pub sub: Region<'a>,
-    pub ty_sup: &'a Ty<'a>,
-    pub ty_sub: &'a Ty<'a>,
+    pub ty_sup: &'a hir::Ty<'a>,
+    pub ty_sub: &'a hir::Ty<'a>,
     pub add_note: bool,
 }
 
@@ -369,8 +372,8 @@ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
     {
         let mut mk_suggestion = || {
             let (
-                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
-                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+                hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
+                hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
             ) = (self.ty_sub, self.ty_sup) else {
                 return false;
             };
@@ -520,3 +523,411 @@ pub struct MismatchedStaticLifetime<'a> {
     #[subdiagnostic]
     pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
 }
+
+#[derive(Diagnostic)]
+pub enum ExplicitLifetimeRequired<'a> {
+    #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")]
+    WithIdent {
+        #[primary_span]
+        #[label]
+        span: Span,
+        simple_ident: Ident,
+        named: String,
+        #[suggestion(
+            infer_explicit_lifetime_required_sugg_with_ident,
+            code = "{new_ty}",
+            applicability = "unspecified"
+        )]
+        new_ty_span: Span,
+        #[skip_arg]
+        new_ty: Ty<'a>,
+    },
+    #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")]
+    WithParamType {
+        #[primary_span]
+        #[label]
+        span: Span,
+        named: String,
+        #[suggestion(
+            infer_explicit_lifetime_required_sugg_with_param_type,
+            code = "{new_ty}",
+            applicability = "unspecified"
+        )]
+        new_ty_span: Span,
+        #[skip_arg]
+        new_ty: Ty<'a>,
+    },
+}
+
+pub enum TyOrSig<'tcx> {
+    Ty(Highlighted<'tcx, Ty<'tcx>>),
+    ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
+}
+
+impl IntoDiagnosticArg for TyOrSig<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        match self {
+            TyOrSig::Ty(ty) => ty.into_diagnostic_arg(),
+            TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(),
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub enum ActualImplExplNotes<'tcx> {
+    #[note(infer_actual_impl_expl_expected_signature_two)]
+    ExpectedSignatureTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_signature_any)]
+    ExpectedSignatureAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_signature_some)]
+    ExpectedSignatureSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_signature_nothing)]
+    ExpectedSignatureNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_two)]
+    ExpectedPassiveTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_any)]
+    ExpectedPassiveAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_some)]
+    ExpectedPassiveSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_nothing)]
+    ExpectedPassiveNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(infer_actual_impl_expl_expected_other_two)]
+    ExpectedOtherTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_other_any)]
+    ExpectedOtherAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_other_some)]
+    ExpectedOtherSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_other_nothing)]
+    ExpectedOtherNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(infer_actual_impl_expl_but_actually_implements_trait)]
+    ButActuallyImplementsTrait {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+    },
+    #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)]
+    ButActuallyImplementedForTy {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+        ty: String,
+    },
+    #[note(infer_actual_impl_expl_but_actually_ty_implements)]
+    ButActuallyTyImplements {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+        ty: String,
+    },
+}
+
+pub enum ActualImplExpectedKind {
+    Signature,
+    Passive,
+    Other,
+}
+
+pub enum ActualImplExpectedLifetimeKind {
+    Two,
+    Any,
+    Some,
+    Nothing,
+}
+
+impl<'tcx> ActualImplExplNotes<'tcx> {
+    pub fn new_expected(
+        kind: ActualImplExpectedKind,
+        lt_kind: ActualImplExpectedLifetimeKind,
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    ) -> Self {
+        match (kind, lt_kind) {
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedSignatureTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedPassiveTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedOtherTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_trait_placeholder_mismatch)]
+pub struct TraitPlaceholderMismatch<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label(label_satisfy)]
+    pub satisfy_span: Option<Span>,
+    #[label(label_where)]
+    pub where_span: Option<Span>,
+    #[label(label_dup)]
+    pub dup_span: Option<Span>,
+    pub def_id: String,
+    pub trait_def_id: String,
+
+    #[subdiagnostic]
+    pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
+}
+
+pub struct ConsiderBorrowingParamHelp {
+    pub spans: Vec<Span>,
+}
+
+impl AddToDiagnostic for ConsiderBorrowingParamHelp {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        let mut type_param_span: MultiSpan = self.spans.clone().into();
+        for &span in &self.spans {
+            // Seems like we can't call f() here as Into<DiagnosticMessage> is required
+            type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing);
+        }
+        let msg = f(diag, fluent::infer_tid_param_help.into());
+        diag.span_help(type_param_span, msg);
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[help(infer_tid_rel_help)]
+pub struct RelationshipHelp;
+
+#[derive(Diagnostic)]
+#[diag(infer_trait_impl_diff)]
+pub struct TraitImplDiff {
+    #[primary_span]
+    #[label(found)]
+    pub sp: Span,
+    #[label(expected)]
+    pub trait_sp: Span,
+    #[note(expected_found)]
+    pub note: (),
+    #[subdiagnostic]
+    pub param_help: ConsiderBorrowingParamHelp,
+    #[subdiagnostic]
+    // Seems like subdiagnostics are always pushed to the end, so this one
+    // also has to be a subdiagnostic to maintain order.
+    pub rel_help: Option<RelationshipHelp>,
+    pub expected: String,
+    pub found: String,
+}
+
+pub struct DynTraitConstraintSuggestion {
+    pub span: Span,
+    pub ident: Ident,
+}
+
+impl AddToDiagnostic for DynTraitConstraintSuggestion {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        let mut multi_span: MultiSpan = vec![self.span].into();
+        multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
+        multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement);
+        let msg = f(diag, fluent::infer_dtcs_has_req_note.into());
+        diag.span_note(multi_span, msg);
+        let msg = f(diag, fluent::infer_dtcs_suggestion.into());
+        diag.span_suggestion_verbose(
+            self.span.shrink_to_hi(),
+            msg,
+            " + '_",
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_but_calling_introduces, code = "E0772")]
+pub struct ButCallingIntroduces {
+    #[label(label1)]
+    pub param_ty_span: Span,
+    #[primary_span]
+    #[label(label2)]
+    pub cause_span: Span,
+
+    pub has_param_name: bool,
+    pub param_name: String,
+    pub has_lifetime: bool,
+    pub lifetime: String,
+    pub assoc_item: Symbol,
+    pub has_impl_path: bool,
+    pub impl_path: String,
+}
+
+pub struct ReqIntroducedLocations {
+    pub span: MultiSpan,
+    pub spans: Vec<Span>,
+    pub fn_decl_span: Span,
+    pub cause_span: Span,
+    pub add_label: bool,
+}
+
+impl AddToDiagnostic for ReqIntroducedLocations {
+    fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        for sp in self.spans {
+            self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
+        }
+
+        if self.add_label {
+            self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by);
+        }
+        self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of);
+        let msg = f(diag, fluent::infer_ril_static_introduced_by.into());
+        diag.span_note(self.span, msg);
+    }
+}
+
+pub struct MoreTargeted {
+    pub ident: Symbol,
+}
+
+impl AddToDiagnostic for MoreTargeted {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        diag.code(rustc_errors::error_code!(E0772));
+        diag.set_primary_message(fluent::infer_more_targeted);
+        diag.set_arg("ident", self.ident);
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_but_needs_to_satisfy, code = "E0759")]
+pub struct ButNeedsToSatisfy {
+    #[primary_span]
+    pub sp: Span,
+    #[label(influencer)]
+    pub influencer_point: Span,
+    #[label(used_here)]
+    pub spans: Vec<Span>,
+    #[label(require)]
+    pub require_span_as_label: Option<Span>,
+    #[note(require)]
+    pub require_span_as_note: Option<Span>,
+    #[note(introduced_by_bound)]
+    pub bound: Option<Span>,
+
+    #[subdiagnostic]
+    pub req_introduces_loc: Option<ReqIntroducedLocations>,
+
+    pub spans_empty: bool,
+    pub has_lifetime: bool,
+    pub lifetime: String,
+}
index e9186540a7b7c53869366303bba18d2791432f5f..d816a9ed3d7c102517e024ac39f0d9a3eb52e863 100644 (file)
@@ -427,3 +427,15 @@ fn to_trace(
         }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
+    fn to_trace(
+        _: TyCtxt<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) }
+    }
+}
index ec5221379d2c9314f93dedab1163b409569203e6..091635e6c73c0b1c18cbac1a16c83b3bb85b537a 100644 (file)
@@ -6,8 +6,7 @@
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
 use crate::infer::canonical::{
-    Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized,
-    OriginalQueryValues,
+    Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
 use rustc_middle::ty::flags::FlagComputation;
@@ -40,7 +39,7 @@ pub fn canonicalize_query<V>(
         &self,
         value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -59,7 +58,7 @@ pub fn canonicalize_query_preserving_universes<V>(
         &self,
         value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -99,7 +98,7 @@ pub fn canonicalize_query_preserving_universes<V>(
     /// out the [chapter in the rustc dev guide][c].
     ///
     /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
-    pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V>
+    pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -113,7 +112,7 @@ pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V>
         )
     }
 
-    pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonicalized<'tcx, V>
+    pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -135,7 +134,7 @@ pub fn canonicalize_query_keep_static<V>(
         &self,
         value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -524,7 +523,7 @@ fn canonicalize<V>(
         tcx: TyCtxt<'tcx>,
         canonicalize_region_mode: &dyn CanonicalizeMode,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
index a722613e3310efacb04b8636609c2dff4772e5c7..108011013f58b686a8f6a983e57e94630f7ab204 100644 (file)
@@ -9,7 +9,7 @@
 
 use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
 use crate::infer::canonical::{
-    Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues,
+    Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
     QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
 };
 use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
@@ -57,7 +57,7 @@ pub fn make_canonicalized_query_response<T>(
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+    ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
     where
         T: Debug + TypeFoldable<'tcx>,
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
index 96a976fb89e0fe8f15fdf680787893d676315771..5c3e9a2d5cccd904de3a8d9756f5fb9ef7ba82c8 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
 //! Error Reporting Code for the inference engine
 //!
 //! Because of the way inference, and in particular region inference,
@@ -303,6 +302,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
                     None,
                     format!("captures `{}`", hidden_region),
                     None,
+                    Some(reg_info.def_id),
                 )
             }
         }
@@ -729,7 +729,7 @@ fn note_error_origin(
                             format!("this and all prior arms are found to be of type `{}`", t),
                         );
                     }
-                    let outer_error_span = if any_multiline_arm {
+                    let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
                         // Cover just `match` and the scrutinee expression, not
                         // the entire match body, to reduce diagram noise.
                         cause.span.shrink_to_lo().to(scrut_span)
@@ -737,7 +737,7 @@ fn note_error_origin(
                         cause.span
                     };
                     let msg = "`match` arms have incompatible types";
-                    err.span_label(outer_error_span, msg);
+                    err.span_label(outer, msg);
                     self.suggest_remove_semi_or_return_binding(
                         err,
                         prior_arm_block_id,
@@ -1428,8 +1428,8 @@ struct OpaqueTypesVisitor<'tcx> {
         impl<'tcx> OpaqueTypesVisitor<'tcx> {
             fn visit_expected_found(
                 tcx: TyCtxt<'tcx>,
-                expected: Ty<'tcx>,
-                found: Ty<'tcx>,
+                expected: impl TypeVisitable<'tcx>,
+                found: impl TypeVisitable<'tcx>,
                 ignore_span: Span,
             ) -> Self {
                 let mut types_visitor = OpaqueTypesVisitor {
@@ -1569,6 +1569,11 @@ enum Mismatch<'a> {
                             _ => (false, Mismatch::Fixed("type")),
                         }
                     }
+                    ValuePairs::Sigs(infer::ExpectedFound { expected, found }) => {
+                        OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+                            .report(diag);
+                        (false, Mismatch::Fixed("signature"))
+                    }
                     ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
                         (false, Mismatch::Fixed("trait"))
                     }
@@ -1836,7 +1841,7 @@ enum Similar<'tcx> {
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
         // it's an actual definition. According to the comments (e.g. in
-        // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
+        // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter
         // is relied upon by some other code. This might (or might not) need cleanup.
         let body_owner_def_id =
             self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -2040,6 +2045,17 @@ fn values_str(
                     ret => ret,
                 }
             }
+            infer::Sigs(exp_found) => {
+                let exp_found = self.resolve_vars_if_possible(exp_found);
+                if exp_found.references_error() {
+                    return None;
+                }
+                let (exp, fnd) = self.cmp_fn_sig(
+                    &ty::Binder::dummy(exp_found.expected),
+                    &ty::Binder::dummy(exp_found.found),
+                );
+                Some((exp, fnd, None, None))
+            }
         }
     }
 
index d8f540b74465d46c1ad725a6c18b27c86330d2f0..39f4d5022598d05acfd70ba263fb04c2c239826c 100644 (file)
@@ -96,8 +96,8 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
                 }
             }
 
-            hir::TyKind::Rptr(ref lifetime, _) => {
-                // the lifetime of the TyRptr
+            hir::TyKind::Ref(ref lifetime, _) => {
+                // the lifetime of the Ref
                 let hir_id = lifetime.hir_id;
                 match (self.tcx.named_region(hir_id), self.bound_region) {
                     // Find the index of the named region that was part of the
index 8a0e332f9c704b4f5f958e6f59bd546c65fa629a..59fb74eb54378f0c1e836c33214251659871d701 100644 (file)
@@ -9,7 +9,7 @@
 pub mod find_anon_type;
 mod mismatched_static_lifetime;
 mod named_anon_conflict;
-mod placeholder_error;
+pub(crate) mod placeholder_error;
 mod placeholder_relation;
 mod static_impl_trait;
 mod trait_impl_difference;
index 3fe7c1598fc3fbbf2e6ad540f2b2e9a557387e40..4e13ec90228d66c8b451cb885b17ed794094e258 100644 (file)
@@ -1,8 +1,11 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where one region is named and the other is anonymous.
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use crate::{
+    errors::ExplicitLifetimeRequired,
+    infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
+};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_middle::ty;
 use rustc_span::symbol::kw;
 
@@ -86,31 +89,17 @@ pub(super) fn try_report_named_anon_conflict(
         {
             return None;
         }
-
-        let (error_var, span_label_var) = match param.pat.simple_ident() {
-            Some(simple_ident) => (
-                format!("the type of `{}`", simple_ident),
-                format!("the type of `{}`", simple_ident),
-            ),
-            None => ("parameter type".to_owned(), "type".to_owned()),
+        let named = named.to_string();
+        let err = match param.pat.simple_ident() {
+            Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
+                span,
+                simple_ident,
+                named,
+                new_ty_span,
+                new_ty,
+            },
+            None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
         };
-
-        let mut diag = struct_span_err!(
-            self.tcx().sess,
-            span,
-            E0621,
-            "explicit lifetime required in {}",
-            error_var
-        );
-
-        diag.span_label(span, format!("lifetime `{}` required", named));
-        diag.span_suggestion(
-            new_ty_span,
-            &format!("add explicit lifetime `{}` to {}", named, span_label_var),
-            new_ty,
-            Applicability::Unspecified,
-        );
-
-        Some(diag)
+        Some(self.tcx().sess.parse_sess.create_err(err))
     }
 }
index fed9fda74bfb33ec462dfadf8200f54432691762..202f39521e967d7283fbfe8b747ccb94788878ed 100644 (file)
@@ -1,10 +1,14 @@
+use crate::errors::{
+    ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
+    TraitPlaceholderMismatch, TyOrSig,
+};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::ValuePairs;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::intern::Interned;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
 
-use std::fmt::{self, Write};
+use std::fmt;
+
+// HACK(eddyb) maybe move this in a more central location.
+#[derive(Copy, Clone)]
+pub struct Highlighted<'tcx, T> {
+    tcx: TyCtxt<'tcx>,
+    highlight: RegionHighlightMode<'tcx>,
+    value: T,
+}
+
+impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
+where
+    T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
+    }
+}
+
+impl<'tcx, T> Highlighted<'tcx, T> {
+    fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
+        Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
+    }
+}
+
+impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
+where
+    T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
+        printer.region_highlight_mode = self.highlight;
+
+        let s = self.value.print(printer)?.into_buffer();
+        f.write_str(&s)
+    }
+}
 
 impl<'tcx> NiceRegionError<'_, 'tcx> {
     /// When given a `ConcreteFailure` for a function with arguments containing a named region and
@@ -205,26 +245,21 @@ fn report_trait_placeholder_mismatch(
         actual_substs: SubstsRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let span = cause.span();
-        let msg = format!(
-            "implementation of `{}` is not general enough",
-            self.tcx().def_path_str(trait_def_id),
-        );
-        let mut err = self.tcx().sess.struct_span_err(span, &msg);
-
-        let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
-        | ObligationCauseCode::ExprItemObligation(def_id, ..) =
-            *cause.code()
-        {
-            err.span_label(span, "doesn't satisfy where-clause");
-            err.span_label(
-                self.tcx().def_span(def_id),
-                &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
-            );
-            true
-        } else {
-            err.span_label(span, &msg);
-            false
-        };
+
+        let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
+            if let ObligationCauseCode::ItemObligation(def_id)
+            | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+            {
+                (
+                    true,
+                    Some(span),
+                    Some(self.tcx().def_span(def_id)),
+                    None,
+                    self.tcx().def_path_str(def_id),
+                )
+            } else {
+                (false, None, None, Some(span), String::new())
+            };
 
         let expected_trait_ref = self
             .cx
@@ -284,8 +319,7 @@ fn report_trait_placeholder_mismatch(
             ?expected_self_ty_has_vid,
         );
 
-        self.explain_actual_impl_that_was_found(
-            &mut err,
+        let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
             sub_placeholder,
             sup_placeholder,
             has_sub,
@@ -299,7 +333,15 @@ fn report_trait_placeholder_mismatch(
             leading_ellipsis,
         );
 
-        err
+        self.tcx().sess.create_err(TraitPlaceholderMismatch {
+            span,
+            satisfy_span,
+            where_span,
+            dup_span,
+            def_id,
+            trait_def_id: self.tcx().def_path_str(trait_def_id),
+            actual_impl_expl_notes,
+        })
     }
 
     /// Add notes with details about the expected and actual trait refs, with attention to cases
@@ -309,7 +351,6 @@ fn report_trait_placeholder_mismatch(
     /// due to the number of combinations we have to deal with.
     fn explain_actual_impl_that_was_found(
         &self,
-        err: &mut Diagnostic,
         sub_placeholder: Option<Region<'tcx>>,
         sup_placeholder: Option<Region<'tcx>>,
         has_sub: Option<usize>,
@@ -321,39 +362,7 @@ fn explain_actual_impl_that_was_found(
         actual_has_vid: Option<usize>,
         any_self_ty_has_vid: bool,
         leading_ellipsis: bool,
-    ) {
-        // HACK(eddyb) maybe move this in a more central location.
-        #[derive(Copy, Clone)]
-        struct Highlighted<'tcx, T> {
-            tcx: TyCtxt<'tcx>,
-            highlight: RegionHighlightMode<'tcx>,
-            value: T,
-        }
-
-        impl<'tcx, T> Highlighted<'tcx, T> {
-            fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
-                Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
-            }
-        }
-
-        impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
-        where
-            T: for<'a> Print<
-                'tcx,
-                FmtPrinter<'a, 'tcx>,
-                Error = fmt::Error,
-                Output = FmtPrinter<'a, 'tcx>,
-            >,
-        {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
-                printer.region_highlight_mode = self.highlight;
-
-                let s = self.value.print(printer)?.into_buffer();
-                f.write_str(&s)
-            }
-        }
-
+    ) -> Vec<ActualImplExplNotes<'tcx>> {
         // The weird thing here with the `maybe_highlighting_region` calls and the
         // the match inside is meant to be like this:
         //
@@ -380,120 +389,110 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
         expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
         expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
-        err.note(&{
-            let passive_voice = match (has_sub, has_sup) {
-                (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
-                (None, None) => {
-                    expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
-                    match expected_has_vid {
-                        Some(_) => true,
-                        None => any_self_ty_has_vid,
-                    }
-                }
-            };
 
-            let mut note = if same_self_type {
-                let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
-                self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
-
-                if self_ty.value.is_closure()
-                    && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
-                {
-                    let closure_sig = self_ty.map(|closure| {
-                        if let ty::Closure(_, substs) = closure.kind() {
-                            self.tcx().signature_unclosure(
-                                substs.as_closure().sig(),
-                                rustc_hir::Unsafety::Normal,
-                            )
-                        } else {
-                            bug!("type is not longer closure");
-                        }
-                    });
-
-                    format!(
-                        "{}closure with signature `{}` must implement `{}`",
-                        if leading_ellipsis { "..." } else { "" },
-                        closure_sig,
-                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    )
-                } else {
-                    format!(
-                        "{}`{}` must implement `{}`",
-                        if leading_ellipsis { "..." } else { "" },
-                        self_ty,
-                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    )
+        let passive_voice = match (has_sub, has_sup) {
+            (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
+            (None, None) => {
+                expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
+                match expected_has_vid {
+                    Some(_) => true,
+                    None => any_self_ty_has_vid,
                 }
-            } else if passive_voice {
-                format!(
-                    "{}`{}` would have to be implemented for the type `{}`",
-                    if leading_ellipsis { "..." } else { "" },
+            }
+        };
+
+        let (kind, ty_or_sig, trait_path) = if same_self_type {
+            let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+            self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+            if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
+            {
+                let closure_sig = self_ty.map(|closure| {
+                    if let ty::Closure(_, substs) = closure.kind() {
+                        self.tcx().signature_unclosure(
+                            substs.as_closure().sig(),
+                            rustc_hir::Unsafety::Normal,
+                        )
+                    } else {
+                        bug!("type is not longer closure");
+                    }
+                });
+                (
+                    ActualImplExpectedKind::Signature,
+                    TyOrSig::ClosureSig(closure_sig),
                     expected_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    expected_trait_ref.map(|tr| tr.self_ty()),
                 )
             } else {
-                format!(
-                    "{}`{}` must implement `{}`",
-                    if leading_ellipsis { "..." } else { "" },
-                    expected_trait_ref.map(|tr| tr.self_ty()),
+                (
+                    ActualImplExpectedKind::Other,
+                    TyOrSig::Ty(self_ty),
                     expected_trait_ref.map(|tr| tr.print_only_trait_path()),
                 )
-            };
+            }
+        } else if passive_voice {
+            (
+                ActualImplExpectedKind::Passive,
+                TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+                expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+            )
+        } else {
+            (
+                ActualImplExpectedKind::Other,
+                TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+                expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+            )
+        };
 
-            match (has_sub, has_sup) {
-                (Some(n1), Some(n2)) => {
-                    let _ = write!(
-                        note,
-                        ", for any two lifetimes `'{}` and `'{}`...",
-                        std::cmp::min(n1, n2),
-                        std::cmp::max(n1, n2),
-                    );
-                }
-                (Some(n), _) | (_, Some(n)) => {
-                    let _ = write!(note, ", for any lifetime `'{}`...", n,);
-                }
-                (None, None) => {
-                    if let Some(n) = expected_has_vid {
-                        let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
-                    }
+        let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
+            (Some(n1), Some(n2)) => {
+                (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
+            }
+            (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
+            (None, None) => {
+                if let Some(n) = expected_has_vid {
+                    (ActualImplExpectedLifetimeKind::Some, n, 0)
+                } else {
+                    (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
                 }
             }
+        };
 
-            note
-        });
+        let note_1 = ActualImplExplNotes::new_expected(
+            kind,
+            lt_kind,
+            leading_ellipsis,
+            ty_or_sig,
+            trait_path,
+            lifetime_1,
+            lifetime_2,
+        );
 
         let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
         actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
-        err.note(&{
-            let passive_voice = match actual_has_vid {
-                Some(_) => any_self_ty_has_vid,
-                None => true,
-            };
 
-            let mut note = if same_self_type {
-                format!(
-                    "...but it actually implements `{}`",
-                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
-                )
-            } else if passive_voice {
-                format!(
-                    "...but `{}` is actually implemented for the type `{}`",
-                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    actual_trait_ref.map(|tr| tr.self_ty()),
-                )
-            } else {
-                format!(
-                    "...but `{}` actually implements `{}`",
-                    actual_trait_ref.map(|tr| tr.self_ty()),
-                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
-                )
-            };
+        let passive_voice = match actual_has_vid {
+            Some(_) => any_self_ty_has_vid,
+            None => true,
+        };
 
-            if let Some(n) = actual_has_vid {
-                let _ = write!(note, ", for some specific lifetime `'{}`", n);
+        let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
+        let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
+        let has_lifetime = actual_has_vid.is_some();
+        let lifetime = actual_has_vid.unwrap_or_default();
+
+        let note_2 = if same_self_type {
+            ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
+        } else if passive_voice {
+            ActualImplExplNotes::ButActuallyImplementedForTy {
+                trait_path,
+                ty,
+                has_lifetime,
+                lifetime,
             }
+        } else {
+            ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
+        };
 
-            note
-        });
+        vec![note_1, note_2]
     }
 }
index 9bd2202d2601e6f54dcb7a7bac0a5c001e2eb325..fb0f09198ccc185330064cb2b7df525d1048f26c 100644 (file)
@@ -1,20 +1,28 @@
 //! Error Reporting for static impl Traits.
 
+use crate::errors::{
+    ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+    ReqIntroducedLocations,
+};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
+use rustc_hir::{
+    self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
+    TyKind,
+};
 use rustc_middle::ty::{
     self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
+use rustc_span::def_id::LocalDefId;
 use std::ops::ControlFlow;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -49,46 +57,32 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
                     }
 
                     let param = self.find_param_with_region(*sup_r, *sub_r)?;
-                    let lifetime = if sup_r.has_name() {
-                        format!("lifetime `{}`", sup_r)
-                    } else {
-                        "an anonymous lifetime `'_`".to_string()
+                    let simple_ident = param.param.pat.simple_ident();
+
+                    let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
+                        AssocItemContainer::TraitContainer => {
+                            let id = ctxt.assoc_item.container_id(tcx);
+                            (true, tcx.def_path_str(id))
+                        }
+                        AssocItemContainer::ImplContainer => (false, String::new()),
                     };
-                    let mut err = struct_span_err!(
-                        tcx.sess,
-                        cause.span,
-                        E0772,
-                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
-                         requirement",
-                        param
-                            .param
-                            .pat
-                            .simple_ident()
-                            .map(|s| format!("`{}`", s))
-                            .unwrap_or_else(|| "`fn` parameter".to_string()),
-                        lifetime,
-                        ctxt.assoc_item.name,
-                    );
-                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
-                    err.span_label(
-                        cause.span,
-                        &format!(
-                            "...is used and required to live as long as `'static` here \
-                             because of an implicit lifetime bound on the {}",
-                            match ctxt.assoc_item.container {
-                                AssocItemContainer::TraitContainer => {
-                                    let id = ctxt.assoc_item.container_id(tcx);
-                                    format!("`impl` of `{}`", tcx.def_path_str(id))
-                                }
-                                AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
-                            },
-                        ),
-                    );
+
+                    let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
+                        param_ty_span: param.param_ty_span,
+                        cause_span: cause.span,
+                        has_param_name: simple_ident.is_some(),
+                        param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
+                        has_lifetime: sup_r.has_name(),
+                        lifetime: sup_r.to_string(),
+                        assoc_item: ctxt.assoc_item.name,
+                        has_impl_path,
+                        impl_path,
+                    });
                     if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
                         let reported = err.emit();
                         return Some(reported);
                     } else {
-                        err.cancel();
+                        err.cancel()
                     }
                 }
                 return None;
@@ -104,25 +98,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
         let sp = var_origin.span();
         let return_sp = sub_origin.span();
         let param = self.find_param_with_region(*sup_r, *sub_r)?;
-        let (lifetime_name, lifetime) = if sup_r.has_name() {
-            (sup_r.to_string(), format!("lifetime `{}`", sup_r))
-        } else {
-            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
-        };
-        let param_name = param
-            .param
-            .pat
-            .simple_ident()
-            .map(|s| format!("`{}`", s))
-            .unwrap_or_else(|| "`fn` parameter".to_string());
-        let mut err = struct_span_err!(
-            tcx.sess,
-            sp,
-            E0759,
-            "{} has {} but it needs to satisfy a `'static` lifetime requirement",
-            param_name,
-            lifetime,
-        );
+        let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
 
         let (mention_influencer, influencer_point) =
             if sup_origin.span().overlaps(param.param_ty_span) {
@@ -141,7 +117,6 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
             } else {
                 (!sup_origin.span().overlaps(return_sp), param.param_ty_span)
             };
-        err.span_label(influencer_point, &format!("this data with {}...", lifetime));
 
         debug!("try_report_static_impl_trait: param_info={:?}", param);
 
@@ -155,31 +130,19 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
         spans.dedup_by_key(|span| (span.lo(), span.hi()));
 
         // We try to make the output have fewer overlapping spans if possible.
-        let require_msg = if spans.is_empty() {
-            "...is used and required to live as long as `'static` here"
-        } else {
-            "...and is required to live as long as `'static` here"
-        };
         let require_span =
             if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
 
-        for span in &spans {
-            err.span_label(*span, "...is used here...");
-        }
-
-        if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
-            // If any of the "captured here" labels appears on the same line or after
-            // `require_span`, we put it on a note to ensure the text flows by appearing
-            // always at the end.
-            err.span_note(require_span, require_msg);
+        let spans_empty = spans.is_empty();
+        let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
+        let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+            Some(*bound)
         } else {
-            // We don't need a note, it's already at the end, it can be shown as a `span_label`.
-            err.span_label(require_span, require_msg);
-        }
+            None
+        };
+
+        let mut subdiag = None;
 
-        if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
-            err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
-        }
         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
             if let ObligationCauseCode::ReturnValue(hir_id)
             | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
@@ -187,33 +150,50 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
                 let parent_id = tcx.hir().get_parent_item(*hir_id);
                 if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
                     let mut span: MultiSpan = fn_decl.output.span().into();
+                    let mut spans = Vec::new();
                     let mut add_label = true;
                     if let hir::FnRetTy::Return(ty) = fn_decl.output {
                         let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
                         v.visit_ty(ty);
                         if !v.0.is_empty() {
                             span = v.0.clone().into();
-                            for sp in v.0 {
-                                span.push_span_label(sp, "`'static` requirement introduced here");
-                            }
+                            spans = v.0;
                             add_label = false;
                         }
                     }
-                    if add_label {
-                        span.push_span_label(
-                            fn_decl.output.span(),
-                            "requirement introduced by this return type",
-                        );
-                    }
-                    span.push_span_label(cause.span, "because of this returned expression");
-                    err.span_note(
+                    let fn_decl_span = fn_decl.output.span();
+
+                    subdiag = Some(ReqIntroducedLocations {
                         span,
-                        "`'static` lifetime requirement introduced by the return type",
-                    );
+                        spans,
+                        fn_decl_span,
+                        cause_span: cause.span,
+                        add_label,
+                    });
                 }
             }
         }
 
+        let diag = ButNeedsToSatisfy {
+            sp,
+            influencer_point,
+            spans: spans.clone(),
+            // If any of the "captured here" labels appears on the same line or after
+            // `require_span`, we put it on a note to ensure the text flows by appearing
+            // always at the end.
+            require_span_as_note: require_as_note.then_some(require_span),
+            // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+            require_span_as_label: (!require_as_note).then_some(require_span),
+            req_introduces_loc: subdiag,
+
+            has_lifetime: sup_r.has_name(),
+            lifetime: sup_r.to_string(),
+            spans_empty,
+            bound,
+        };
+
+        let mut err = self.tcx().sess.create_err(diag);
+
         let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
 
         let mut override_error_code = None;
@@ -239,7 +219,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
             let mut v = TraitObjectVisitor(FxIndexSet::default());
             v.visit_ty(param.param_ty);
             if let Some((ident, self_ty)) =
-                self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+                NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
                 && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
             {
                 override_error_code = Some(ident.name);
@@ -247,12 +227,8 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
         }
         if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
             // Provide a more targeted error code and description.
-            err.code(rustc_errors::error_code!(E0772));
-            err.set_primary_message(&format!(
-                "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
-                requirement",
-                param_name, lifetime, ident,
-            ));
+            let retarget_subdiag = MoreTargeted { ident };
+            retarget_subdiag.add_to_diagnostic(&mut err);
         }
 
         let arg = match param.param.pat.simple_ident() {
@@ -268,6 +244,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
             Some(arg),
             captures,
             Some((param.param_ty_span, param.param_ty.to_string())),
+            Some(anon_reg_sup.def_id),
         );
 
         let reported = err.emit();
@@ -283,6 +260,7 @@ pub fn suggest_new_region_bound(
     arg: Option<String>,
     captures: String,
     param: Option<(Span, String)>,
+    scope_def_id: Option<LocalDefId>,
 ) {
     debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
     // FIXME: account for the need of parens in `&(dyn Trait + '_)`
@@ -309,19 +287,12 @@ pub fn suggest_new_region_bound(
                 let did = item_id.owner_id.to_def_id();
                 let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
 
-                if let Some(span) = opaque
-                    .bounds
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        GenericBound::Outlives(Lifetime {
-                            res: LifetimeName::Static,
-                            ident,
-                            ..
-                        }) => Some(ident.span),
-                        _ => None,
-                    })
-                    .next()
-                {
+                if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+                    GenericBound::Outlives(Lifetime {
+                        res: LifetimeName::Static, ident, ..
+                    }) => Some(ident.span),
+                    _ => None,
+                }) {
                     if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             span,
@@ -338,27 +309,78 @@ pub fn suggest_new_region_bound(
                             Applicability::MaybeIncorrect,
                         );
                     }
-                } else if opaque
-                    .bounds
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        GenericBound::Outlives(Lifetime { ident, .. })
-                            if ident.name.to_string() == lifetime_name =>
-                        {
-                            Some(ident.span)
-                        }
-                        _ => None,
-                    })
-                    .next()
-                    .is_some()
-                {
+                } else if opaque.bounds.iter().any(|arg| match arg {
+                    GenericBound::Outlives(Lifetime { ident, .. })
+                        if ident.name.to_string() == lifetime_name =>
+                    {
+                        true
+                    }
+                    _ => false,
+                }) {
                 } else {
-                    err.span_suggestion_verbose(
-                        fn_return.span.shrink_to_hi(),
-                        &format!("{declare} `{ty}` {captures}, {explicit}",),
-                        &plus_lt,
-                        Applicability::MaybeIncorrect,
-                    );
+                    // get a lifetime name of existing named lifetimes if any
+                    let existing_lt_name = if let Some(id) = scope_def_id
+                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let named_lifetimes = generics
+                        .params
+                        .iter()
+                        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
+                        .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
+                        .filter(|n| ! matches!(n, None))
+                        .collect::<Vec<_>>()
+                        && named_lifetimes.len() > 0 {
+                        named_lifetimes[0].clone()
+                    } else {
+                        None
+                    };
+                    let name = if let Some(name) = &existing_lt_name {
+                        format!("{}", name)
+                    } else {
+                        format!("'a")
+                    };
+                    // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
+                    // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
+                    if let Some(id) = scope_def_id
+                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let mut spans_suggs = generics
+                            .params
+                            .iter()
+                            .filter(|p| p.is_elided_lifetime())
+                            .map(|p|
+                                  if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
+                                      (p.span.shrink_to_hi(),format!("{name} "))
+                                  } else { // Underscore (elided with '_)
+                                      (p.span, format!("{name}"))
+                                  }
+                            )
+                            .collect::<Vec<_>>()
+                        && spans_suggs.len() > 1
+                    {
+                        let use_lt =
+                        if existing_lt_name == None {
+                            spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
+                            format!("you can introduce a named lifetime parameter `{name}`")
+                        } else {
+                            // make use the existing named lifetime
+                            format!("you can use the named lifetime parameter `{name}`")
+                        };
+                        spans_suggs
+                            .push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
+                        err.multipart_suggestion_verbose(
+                            &format!(
+                                "{declare} `{ty}` {captures}, {use_lt}",
+                            ),
+                            spans_suggs,
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.span_suggestion_verbose(
+                            fn_return.span.shrink_to_hi(),
+                            &format!("{declare} `{ty}` {captures}, {explicit}",),
+                            &plus_lt,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
             }
             TyKind::TraitObject(_, lt, _) => {
@@ -403,66 +425,54 @@ pub fn suggest_new_region_bound(
 }
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
-    fn get_impl_ident_and_self_ty_from_trait(
-        &self,
+    pub fn get_impl_ident_and_self_ty_from_trait(
+        tcx: TyCtxt<'tcx>,
         def_id: DefId,
         trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        let tcx = self.tcx();
-        match tcx.hir().get_if_local(def_id) {
-            Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+        match tcx.hir().get_if_local(def_id)? {
+            Node::ImplItem(impl_item) => {
+                let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+                if let hir::OwnerNode::Item(Item {
+                    kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                    ..
+                }) = tcx.hir().owner(impl_did)
                 {
-                    Some(Node::Item(Item {
-                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                        ..
-                    })) => Some((impl_item.ident, self_ty)),
-                    _ => None,
+                    Some((impl_item.ident, self_ty))
+                } else {
+                    None
                 }
             }
-            Some(Node::TraitItem(trait_item)) => {
-                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did.def_id) {
-                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
-                        // The method being called is defined in the `trait`, but the `'static`
-                        // obligation comes from the `impl`. Find that `impl` so that we can point
-                        // at it in the suggestion.
-                        let trait_did = trait_did.to_def_id();
-                        match tcx
-                            .hir()
-                            .trait_impls(trait_did)
-                            .iter()
-                            .filter_map(|&impl_did| {
-                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
-                                    Some(Node::Item(Item {
-                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                                        ..
-                                    })) if trait_objects.iter().all(|did| {
-                                        // FIXME: we should check `self_ty` against the receiver
-                                        // type in the `UnifyReceiver` context, but for now, use
-                                        // this imperfect proxy. This will fail if there are
-                                        // multiple `impl`s for the same trait like
-                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
-                                        // In that case, only the first one will get suggestions.
-                                        let mut traits = vec![];
-                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
-                                        hir_v.visit_ty(self_ty);
-                                        !traits.is_empty()
-                                    }) =>
-                                    {
-                                        Some(self_ty)
-                                    }
-                                    _ => None,
-                                }
-                            })
-                            .next()
-                        {
-                            Some(self_ty) => Some((trait_item.ident, self_ty)),
-                            _ => None,
-                        }
+            Node::TraitItem(trait_item) => {
+                let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+                debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+                // The method being called is defined in the `trait`, but the `'static`
+                // obligation comes from the `impl`. Find that `impl` so that we can point
+                // at it in the suggestion.
+                let trait_did = trait_id.to_def_id();
+                tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+                    if let Node::Item(Item {
+                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                        ..
+                    }) = tcx.hir().find_by_def_id(impl_did)?
+                        && trait_objects.iter().all(|did| {
+                            // FIXME: we should check `self_ty` against the receiver
+                            // type in the `UnifyReceiver` context, but for now, use
+                            // this imperfect proxy. This will fail if there are
+                            // multiple `impl`s for the same trait like
+                            // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+                            // In that case, only the first one will get suggestions.
+                            let mut traits = vec![];
+                            let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+                            hir_v.visit_ty(self_ty);
+                            !traits.is_empty()
+                        })
+                    {
+                        Some((trait_item.ident, *self_ty))
+                    } else {
+                        None
                     }
-                    _ => None,
-                }
+                })
             }
             _ => None,
         }
@@ -493,7 +503,7 @@ fn find_impl_on_dyn_trait(
 
         // Get the `Ident` of the method being called and the corresponding `impl` (to point at
         // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
-        let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+        let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
             return false;
         };
 
@@ -513,21 +523,9 @@ fn suggest_constrain_dyn_trait_in_impl(
             let mut traits = vec![];
             let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
             hir_v.visit_ty(&self_ty);
-            for span in &traits {
-                let mut multi_span: MultiSpan = vec![*span].into();
-                multi_span
-                    .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
-                multi_span.push_span_label(
-                    ident.span,
-                    "calling this method introduces the `impl`'s 'static` requirement",
-                );
-                err.span_note(multi_span, "the used `impl` has a `'static` requirement");
-                err.span_suggestion_verbose(
-                    span.shrink_to_hi(),
-                    "consider relaxing the implicit `'static` requirement",
-                    " + '_",
-                    Applicability::MaybeIncorrect,
-                );
+            for &span in &traits {
+                let subdiag = DynTraitConstraintSuggestion { span, ident };
+                subdiag.add_to_diagnostic(err);
                 suggested = true;
             }
         }
index 5d536e982ed028af28d6cb4b50e3b3f9d96b2cee..40c0c806e1ff8ea41e8e68de27980fe91e81f4cc 100644 (file)
@@ -1,15 +1,17 @@
 //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
 
+use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::Subtype;
+use crate::infer::{Subtype, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplItemObligation;
-use rustc_errors::{ErrorGuaranteed, MultiSpan};
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::Span;
@@ -22,22 +24,27 @@ pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuar
         let error = self.error.as_ref()?;
         debug!("try_report_impl_not_conforming_to_trait {:?}", error);
         if let RegionResolutionError::SubSupConflict(
-                _,
-                var_origin,
-                sub_origin,
-                _sub,
-                sup_origin,
-                _sup,
-                _,
-            ) = error.clone()
+            _,
+            var_origin,
+            sub_origin,
+            _sub,
+            sup_origin,
+            _sup,
+            _,
+        ) = error.clone()
             && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
-            && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
-            && let sup_expected_found @ Some(_) = sup_trace.values.ty()
             && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
-            && sup_expected_found == sub_expected_found
+            && sub_trace.values == sup_trace.values
+            && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
         {
-            let guar =
-                self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
+            // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
+            // all of the region highlighting machinery only deals with those.
+            let guar = self.emit_err(
+                var_origin.span(),
+                self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)),
+                self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)),
+                *trait_item_def_id,
+            );
             return Some(guar);
         }
         None
@@ -51,10 +58,6 @@ fn emit_err(
         trait_def_id: DefId,
     ) -> ErrorGuaranteed {
         let trait_sp = self.tcx().def_span(trait_def_id);
-        let mut err = self
-            .tcx()
-            .sess
-            .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
 
         // Mark all unnamed regions in the type with a number.
         // This diagnostic is called in response to lifetime errors, so be informative.
@@ -91,9 +94,6 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         let found =
             self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
 
-        err.span_label(sp, &format!("found `{}`", found));
-        err.span_label(trait_sp, &format!("expected `{}`", expected));
-
         // Get the span of all the used type parameters in the method.
         let assoc_item = self.tcx().associated_item(trait_def_id);
         let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
@@ -110,26 +110,18 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             _ => {}
         }
-        let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
-        for &span in &visitor.types {
-            type_param_span
-                .push_span_label(span, "consider borrowing this type parameter in the trait");
-        }
 
-        err.note(&format!("expected `{}`\n   found `{}`", expected, found));
-
-        err.span_help(
-            type_param_span,
-            "the lifetime requirements from the `impl` do not correspond to the requirements in \
-             the `trait`",
-        );
-        if visitor.types.is_empty() {
-            err.help(
-                "verify the lifetime relationships in the `trait` and `impl` between the `self` \
-                 argument, the other inputs and its output",
-            );
-        }
-        err.emit()
+        let diag = TraitImplDiff {
+            sp,
+            trait_sp,
+            note: (),
+            param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
+            rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
+            expected,
+            found,
+        };
+
+        self.tcx().sess.emit_err(diag)
     }
 }
 
@@ -147,7 +139,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
         match arg.kind {
-            hir::TyKind::Rptr(_, ref mut_ty) => {
+            hir::TyKind::Ref(_, ref mut_ty) => {
                 // We don't want to suggest looking into borrowing `&T` or `&Self`.
                 hir::intravisit::walk_ty(self, mut_ty.ty);
                 return;
index d2dffa4a0b78e5ef1d75606e165b0a137fbf87e0..7bb79d7bda8ddf5e2954803da34046a212a45a91 100644 (file)
@@ -2,11 +2,14 @@
 use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
 use crate::infer::{self, SubregionOrigin};
 use rustc_errors::{
-    fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
+    ErrorGuaranteed,
 };
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
+use rustc_middle::ty::{self, IsSuggestable, Region};
+use rustc_span::symbol::kw;
 
 use super::ObligationCauseAsDiagArg;
 
@@ -22,16 +25,6 @@ pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &Subregion
             infer::Reborrow(span) => {
                 RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
             }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reborrow,
-                    name: &var_name.to_string(),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
             infer::RelateObjectBound(span) => {
                 RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
                     .add_to_diagnostic(err);
@@ -159,33 +152,6 @@ pub(super) fn report_concrete_failure(
                 );
                 err
             }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0313,
-                    "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
-                    var_name
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...the borrowed pointer is valid for ",
-                    sub,
-                    "...",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    &format!("...but `{}` is only valid for ", var_name),
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
             infer::RelateObjectBound(span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
@@ -313,55 +279,38 @@ pub(super) fn report_concrete_failure(
                 );
                 err
             }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
-                .report_extra_impl_obligation(
+            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+                let mut err = self.report_extra_impl_obligation(
                     span,
                     impl_item_def_id,
                     trait_item_def_id,
                     &format!("`{}: {}`", sup, sub),
-                ),
+                );
+                // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
+                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+                    && generics.where_clause_span.contains(span)
+                {
+                    self.suggest_copy_trait_method_bounds(
+                        trait_item_def_id,
+                        impl_item_def_id,
+                        &mut err,
+                    );
+                }
+                err
+            }
             infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
                 let mut err = self.report_concrete_failure(*parent, sub, sup);
-
                 let trait_item_span = self.tcx.def_span(trait_item_def_id);
                 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
                 err.span_label(
                     trait_item_span,
                     format!("definition of `{}` from trait", item_name),
                 );
-
-                let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
-                let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
-                let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
-                    impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
-                let clauses: Vec<_> = trait_predicates
-                    .predicates
-                    .into_iter()
-                    .filter(|&(pred, _)| !impl_predicates.contains(pred))
-                    .map(|(pred, _)| format!("{}", pred))
-                    .collect();
-
-                if !clauses.is_empty() {
-                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
-                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
-                    let suggestion = format!(
-                        "{} {}",
-                        generics.add_where_or_trailing_comma(),
-                        clauses.join(", "),
-                    );
-                    err.span_suggestion(
-                        where_clause_span,
-                        &format!(
-                            "try copying {} from the trait",
-                            if clauses.len() > 1 { "these clauses" } else { "this clause" }
-                        ),
-                        suggestion,
-                        rustc_errors::Applicability::MaybeIncorrect,
-                    );
-                }
-
+                self.suggest_copy_trait_method_bounds(
+                    trait_item_def_id,
+                    impl_item_def_id,
+                    &mut err,
+                );
                 err
             }
             infer::AscribeUserTypeProvePredicate(span) => {
@@ -388,6 +337,65 @@ pub(super) fn report_concrete_failure(
         }
     }
 
+    pub fn suggest_copy_trait_method_bounds(
+        &self,
+        trait_item_def_id: DefId,
+        impl_item_def_id: LocalDefId,
+        err: &mut Diagnostic,
+    ) {
+        // FIXME(compiler-errors): Right now this is only being used for region
+        // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
+        // but right now it's not really very smart when it comes to implicit `Sized`
+        // predicates and bounds on the trait itself.
+
+        let Some(impl_def_id) =
+            self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; };
+        let Some(trait_ref) = self
+            .tcx
+            .impl_trait_ref(impl_def_id)
+            else { return; };
+        let trait_substs = trait_ref
+            // Replace the explicit self type with `Self` for better suggestion rendering
+            .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
+            .substs;
+        let trait_item_substs =
+            ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
+                .rebase_onto(self.tcx, impl_def_id, trait_substs);
+
+        let Ok(trait_predicates) = self
+            .tcx
+            .bound_explicit_predicates_of(trait_item_def_id)
+            .map_bound(|p| p.predicates)
+            .subst_iter_copied(self.tcx, trait_item_substs)
+            .map(|(pred, _)| {
+                if pred.is_suggestable(self.tcx, false) {
+                    Ok(pred.to_string())
+                } else {
+                    Err(())
+                }
+            })
+            .collect::<Result<Vec<_>, ()>>() else { return; };
+
+        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
+
+        if trait_predicates.is_empty() {
+            err.span_suggestion_verbose(
+                generics.where_clause_span,
+                "remove the `where` clause",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            let space = if generics.where_clause_span.is_empty() { " " } else { "" };
+            err.span_suggestion_verbose(
+                generics.where_clause_span,
+                "copy the `where` clause predicates from the trait",
+                format!("{space}where {}", trait_predicates.join(", ")),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     pub(super) fn report_placeholder_failure(
         &self,
         placeholder_origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs b/compiler/rustc_infer/src/infer/error_reporting/note_region.rs
deleted file mode 100644 (file)
index 41b115f..0000000
+++ /dev/null
@@ -1,427 +0,0 @@
-use crate::errors::RegionOriginNote;
-use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
-use crate::infer::{self, SubregionOrigin};
-use rustc_errors::{
-    fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
-
-use super::ObligationCauseAsDiagArg;
-
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
-    pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
-        match *origin {
-            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
-                span: trace.cause.span,
-                requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
-                expected_found: self.values_str(trace.values),
-            }
-            .add_to_diagnostic(err),
-            infer::Reborrow(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
-            }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reborrow,
-                    name: &var_name.to_string(),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
-            infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
-                    .add_to_diagnostic(err);
-            }
-            infer::DataBorrowed(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_data_borrowed,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reference_outlives_referent,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_relate_param_bound,
-                    name: &self.ty_to_string(ty),
-                    continues: opt_span.is_some(),
-                }
-                .add_to_diagnostic(err);
-                if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
-                        .add_to_diagnostic(err);
-                }
-            }
-            infer::RelateRegionParamBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
-                    .add_to_diagnostic(err);
-            }
-            infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
-                    .add_to_diagnostic(err);
-            }
-            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
-                self.note_region_origin(err, &parent);
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                RegionOriginNote::Plain {
-                    span,
-                    msg: fluent::infer_ascribe_user_type_prove_predicate,
-                }
-                .add_to_diagnostic(err);
-            }
-        }
-    }
-
-    pub(super) fn report_concrete_failure(
-        &self,
-        origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        match origin {
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                let mut err = self.report_and_explain_type_error(trace, terr);
-                match (*sub, *sup) {
-                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
-                    (ty::RePlaceholder(_), _) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            "",
-                            sup,
-                            " doesn't meet the lifetime requirements",
-                            None,
-                        );
-                    }
-                    (_, ty::RePlaceholder(_)) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            "the required lifetime does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                    _ => {
-                        note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            "...does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                }
-                err
-            }
-            infer::Reborrow(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0312,
-                    "lifetime of reference outlives lifetime of borrowed content..."
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...the reference is valid for ",
-                    sub,
-                    "...",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...but the borrowed content is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0313,
-                    "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
-                    var_name
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...the borrowed pointer is valid for ",
-                    sub,
-                    "...",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    &format!("...but `{}` is only valid for ", var_name),
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::RelateObjectBound(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0476,
-                    "lifetime of the source pointer does not outlive lifetime bound of the \
-                     object type"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "object type is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "source pointer is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0477,
-                    "the type `{}` does not fulfill the required lifetime",
-                    self.ty_to_string(ty)
-                );
-                match *sub {
-                    ty::ReStatic => note_and_explain_region(
-                        self.tcx,
-                        &mut err,
-                        "type must satisfy ",
-                        sub,
-                        if opt_span.is_some() { " as required by this binding" } else { "" },
-                        opt_span,
-                    ),
-                    _ => note_and_explain_region(
-                        self.tcx,
-                        &mut err,
-                        "type must outlive ",
-                        sub,
-                        if opt_span.is_some() { " as required by this binding" } else { "" },
-                        opt_span,
-                    ),
-                }
-                err
-            }
-            infer::RelateRegionParamBound(span) => {
-                let mut err =
-                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "lifetime parameter instantiated with ",
-                    sup,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but lifetime parameter must outlive ",
-                    sub,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::DataBorrowed(ty, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0490,
-                    "a value of type `{}` is borrowed for too long",
-                    self.ty_to_string(ty)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "the type is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but the borrow lasts for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0491,
-                    "in type `{}`, reference has a longer lifetime than the data it references",
-                    self.ty_to_string(ty)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "the pointer is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but the referenced data is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
-                .report_extra_impl_obligation(
-                    span,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                    &format!("`{}: {}`", sup, sub),
-                ),
-            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
-                let mut err = self.report_concrete_failure(*parent, sub, sup);
-
-                let trait_item_span = self.tcx.def_span(trait_item_def_id);
-                let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-                err.span_label(
-                    trait_item_span,
-                    format!("definition of `{}` from trait", item_name),
-                );
-
-                let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
-                let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
-                let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
-                    impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
-                let clauses: Vec<_> = trait_predicates
-                    .predicates
-                    .into_iter()
-                    .filter(|&(pred, _)| !impl_predicates.contains(pred))
-                    .map(|(pred, _)| format!("{}", pred))
-                    .collect();
-
-                if !clauses.is_empty() {
-                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
-                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
-                    let suggestion = format!(
-                        "{} {}",
-                        generics.add_where_or_trailing_comma(),
-                        clauses.join(", "),
-                    );
-                    err.span_suggestion(
-                        where_clause_span,
-                        &format!(
-                            "try copying {} from the trait",
-                            if clauses.len() > 1 { "these clauses" } else { "this clause" }
-                        ),
-                        suggestion,
-                        rustc_errors::Applicability::MaybeIncorrect,
-                    );
-                }
-
-                err
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                let mut err =
-                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "lifetime instantiated with ",
-                    sup,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but lifetime must outlive ",
-                    sub,
-                    "",
-                    None,
-                );
-                err
-            }
-        }
-    }
-
-    pub(super) fn report_placeholder_failure(
-        &self,
-        placeholder_origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        // I can't think how to do better than this right now. -nikomatsakis
-        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
-        match placeholder_origin {
-            infer::Subtype(box ref trace)
-                if matches!(
-                    &trace.cause.code().peel_derives(),
-                    ObligationCauseCode::BindingObligation(..)
-                        | ObligationCauseCode::ExprBindingObligation(..)
-                ) =>
-            {
-                // Hack to get around the borrow checker because trace.cause has an `Rc`.
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
-                    &trace.cause.code().peel_derives()
-                {
-                    let span = *span;
-                    let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
-                    err.span_note(span, "the lifetime requirement is introduced here");
-                    err
-                } else {
-                    unreachable!()
-                }
-            }
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsPlaceholderMismatch;
-                return self.report_and_explain_type_error(trace, terr);
-            }
-            _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
-        }
-    }
-}
index 30ca9f41d6e6f8d73830b5c2b98150ee61e5dd05..5b02956a106c6cafa6775311a49921aafc355433 100644 (file)
@@ -411,7 +411,7 @@ pub(super) fn suggest_let_for_letchains(
         span: Span,
     ) {
         let hir = self.tcx.hir();
-        let fn_hir_id = hir.get_parent_node(cause.body_id);
+        let fn_hir_id = hir.parent_id(cause.body_id);
         if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
             let hir::Node::Item(hir::Item {
                     kind: hir::ItemKind::Fn(_sig, _, body_id), ..
@@ -585,45 +585,42 @@ pub fn consider_returning_binding(
             let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
             local.pat.walk(&mut find_compatible_candidates);
         }
-        match hir.find(hir.get_parent_node(blk.hir_id)) {
-            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
-                match hir.find(hir.get_parent_node(*hir_id)) {
-                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
-                        pat.walk(&mut find_compatible_candidates);
-                    }
-                    Some(
-                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
-                        | hir::Node::ImplItem(hir::ImplItem {
-                            kind: hir::ImplItemKind::Fn(_, body),
-                            ..
-                        })
-                        | hir::Node::TraitItem(hir::TraitItem {
-                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
-                            ..
-                        })
-                        | hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
-                            ..
-                        }),
-                    ) => {
-                        for param in hir.body(*body).params {
-                            param.pat.walk(&mut find_compatible_candidates);
-                        }
-                    }
-                    Some(hir::Node::Expr(hir::Expr {
-                        kind:
-                            hir::ExprKind::If(
-                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
-                                then_block,
-                                _,
-                            ),
+        match hir.find_parent(blk.hir_id) {
+            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) {
+                Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+                    pat.walk(&mut find_compatible_candidates);
+                }
+                Some(
+                    hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+                    | hir::Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(_, body), ..
+                    })
+                    | hir::Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+                        ..
+                    })
+                    | hir::Node::Expr(hir::Expr {
+                        kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
                         ..
-                    })) if then_block.hir_id == *hir_id => {
-                        let_.pat.walk(&mut find_compatible_candidates);
+                    }),
+                ) => {
+                    for param in hir.body(*body).params {
+                        param.pat.walk(&mut find_compatible_candidates);
                     }
-                    _ => {}
                 }
-            }
+                Some(hir::Node::Expr(hir::Expr {
+                    kind:
+                        hir::ExprKind::If(
+                            hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+                            then_block,
+                            _,
+                        ),
+                    ..
+                })) if then_block.hir_id == *hir_id => {
+                    let_.pat.walk(&mut find_compatible_candidates);
+                }
+                _ => {}
+            },
             _ => {}
         }
 
index a9ef91db059a1ccf381749b61b61b92407559152..31b546581e424832ca65c2f4709ca52d50a4b03a 100644 (file)
@@ -361,6 +361,7 @@ pub enum ValuePairs<'tcx> {
     Terms(ExpectedFound<ty::Term<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
+    Sigs(ExpectedFound<ty::FnSig<'tcx>>),
 }
 
 impl<'tcx> ValuePairs<'tcx> {
@@ -409,9 +410,6 @@ pub enum SubregionOrigin<'tcx> {
     /// Creating a pointer `b` to contents of another reference
     Reborrow(Span),
 
-    /// Creating a pointer `b` to contents of an upvar
-    ReborrowUpvar(Span, ty::UpvarId),
-
     /// Data with type `Ty<'tcx>` was borrowed
     DataBorrowed(Ty<'tcx>, Span),
 
@@ -1681,19 +1679,35 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>)
 }
 
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    /// Processes registered region obliations and resolves regions, reporting
+    /// any errors if any were raised. Prefer using this function over manually
+    /// calling `resolve_regions_and_report_errors`.
+    pub fn check_region_obligations_and_report_errors(
+        &self,
+        generic_param_scope: LocalDefId,
+        outlives_env: &OutlivesEnvironment<'tcx>,
+    ) -> Result<(), ErrorGuaranteed> {
+        self.process_registered_region_obligations(
+            outlives_env.region_bound_pairs(),
+            outlives_env.param_env,
+        );
+
+        self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+    }
+
     /// Process the region constraints and report any errors that
     /// result. After this, no more unification operations should be
     /// done -- or the compiler will panic -- but it is legal to use
     /// `resolve_vars_if_possible` as well as `fully_resolve`.
     ///
     /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
-    /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+    /// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`]
     /// to do both of these operations together.
     pub fn resolve_regions_and_report_errors(
         &self,
         generic_param_scope: LocalDefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
-    ) -> Option<ErrorGuaranteed> {
+    ) -> Result<(), ErrorGuaranteed> {
         let errors = self.resolve_regions(outlives_env);
 
         if let None = self.tainted_by_errors() {
@@ -1705,9 +1719,14 @@ pub fn resolve_regions_and_report_errors(
             self.report_region_errors(generic_param_scope, &errors);
         }
 
-        (!errors.is_empty()).then(|| {
-            self.tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")
-        })
+        if errors.is_empty() {
+            Ok(())
+        } else {
+            Err(self
+                .tcx
+                .sess
+                .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
+        }
     }
 
     // [Note-Type-error-reporting]
@@ -1949,7 +1968,6 @@ pub fn span(&self) -> Span {
             RelateParamBound(a, ..) => a,
             RelateRegionParamBound(a) => a,
             Reborrow(a) => a,
-            ReborrowUpvar(a, _) => a,
             DataBorrowed(_, a) => a,
             ReferenceOutlivesReferent(_, a) => a,
             CompareImplItemObligation { span, .. } => span,
diff --git a/compiler/rustc_infer/src/infer/note.rs b/compiler/rustc_infer/src/infer/note.rs
deleted file mode 100644 (file)
index 2ccbd16..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
-    fn note_error_origin(
-        &self,
-        err: &mut Diagnostic,
-        cause: &ObligationCause<'tcx>,
-        exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
-        terr: TypeError<'tcx>,
-    ) {
-        match *cause.code() {
-            ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
-                let ty = self.resolve_vars_if_possible(root_ty);
-                if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
-                {
-                    // don't show type `_`
-                    if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
-                        && let ty::Adt(def, substs) = ty.kind()
-                        && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
-                    {
-                        err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
-                    } else {
-                    err.span_label(span, format!("this expression has type `{}`", ty));
-                }
-                }
-                if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
-                    && ty.is_box() && ty.boxed_ty() == found
-                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
-                {
-                    err.span_suggestion(
-                        span,
-                        "consider dereferencing the boxed value",
-                        format!("*{}", snippet),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
-                err.span_label(span, "expected due to this");
-            }
-            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                arm_block_id,
-                arm_span,
-                arm_ty,
-                prior_arm_block_id,
-                prior_arm_span,
-                prior_arm_ty,
-                source,
-                ref prior_arms,
-                scrut_hir_id,
-                opt_suggest_box_span,
-                scrut_span,
-                ..
-            }) => match source {
-                hir::MatchSource::TryDesugar => {
-                    if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
-                        let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
-                        let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
-                            let arg_expr = args.first().expect("try desugaring call w/out arg");
-                            self.typeck_results.as_ref().and_then(|typeck_results| {
-                                typeck_results.expr_ty_opt(arg_expr)
-                            })
-                        } else {
-                            bug!("try desugaring w/out call expr as scrutinee");
-                        };
-
-                        match scrut_ty {
-                            Some(ty) if expected == ty => {
-                                let source_map = self.tcx.sess.source_map();
-                                err.span_suggestion(
-                                    source_map.end_point(cause.span),
-                                    "try removing this `?`",
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-                _ => {
-                    // `prior_arm_ty` can be `!`, `expected` will have better info when present.
-                    let t = self.resolve_vars_if_possible(match exp_found {
-                        Some(ty::error::ExpectedFound { expected, .. }) => expected,
-                        _ => prior_arm_ty,
-                    });
-                    let source_map = self.tcx.sess.source_map();
-                    let mut any_multiline_arm = source_map.is_multiline(arm_span);
-                    if prior_arms.len() <= 4 {
-                        for sp in prior_arms {
-                            any_multiline_arm |= source_map.is_multiline(*sp);
-                            err.span_label(*sp, format!("this is found to be of type `{}`", t));
-                        }
-                    } else if let Some(sp) = prior_arms.last() {
-                        any_multiline_arm |= source_map.is_multiline(*sp);
-                        err.span_label(
-                            *sp,
-                            format!("this and all prior arms are found to be of type `{}`", t),
-                        );
-                    }
-                    let outer_error_span = if any_multiline_arm {
-                        // Cover just `match` and the scrutinee expression, not
-                        // the entire match body, to reduce diagram noise.
-                        cause.span.shrink_to_lo().to(scrut_span)
-                    } else {
-                        cause.span
-                    };
-                    let msg = "`match` arms have incompatible types";
-                    err.span_label(outer_error_span, msg);
-                    self.suggest_remove_semi_or_return_binding(
-                        err,
-                        prior_arm_block_id,
-                        prior_arm_ty,
-                        prior_arm_span,
-                        arm_block_id,
-                        arm_ty,
-                        arm_span,
-                    );
-                    if let Some(ret_sp) = opt_suggest_box_span {
-                        // Get return type span and point to it.
-                        self.suggest_boxing_for_return_impl_trait(
-                            err,
-                            ret_sp,
-                            prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
-                        );
-                    }
-                }
-            },
-            ObligationCauseCode::IfExpression(box IfExpressionCause {
-                then_id,
-                else_id,
-                then_ty,
-                else_ty,
-                outer_span,
-                opt_suggest_box_span,
-            }) => {
-                let then_span = self.find_block_span_from_hir_id(then_id);
-                let else_span = self.find_block_span_from_hir_id(else_id);
-                err.span_label(then_span, "expected because of this");
-                if let Some(sp) = outer_span {
-                    err.span_label(sp, "`if` and `else` have incompatible types");
-                }
-                self.suggest_remove_semi_or_return_binding(
-                    err,
-                    Some(then_id),
-                    then_ty,
-                    then_span,
-                    Some(else_id),
-                    else_ty,
-                    else_span,
-                );
-                if let Some(ret_sp) = opt_suggest_box_span {
-                    self.suggest_boxing_for_return_impl_trait(
-                        err,
-                        ret_sp,
-                        [then_span, else_span].into_iter(),
-                    );
-                }
-            }
-            ObligationCauseCode::LetElse => {
-                err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
-                err.help("...or use `match` instead of `let...else`");
-            }
-            _ => {
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..)
-                = cause.code().peel_derives()
-                    && let TypeError::RegionsPlaceholderMismatch = terr
-                {
-                    err.span_note( * span,
-                    "the lifetime requirement is introduced here");
-                }
-            }
-        }
-    }
-}
-
-impl<'tcx> InferCtxt<'tcx> {
-    /// Given a [`hir::Block`], get the span of its last expression or
-    /// statement, peeling off any inner blocks.
-    pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
-        let block = block.innermost_block();
-        if let Some(expr) = &block.expr {
-            expr.span
-        } else if let Some(stmt) = block.stmts.last() {
-            // possibly incorrect trailing `;` in the else arm
-            stmt.span
-        } else {
-            // empty block; point at its entirety
-            block.span
-        }
-    }
-
-    /// Given a [`hir::HirId`] for a block, get the span of its last expression
-    /// or statement, peeling off any inner blocks.
-    pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
-        match self.tcx.hir().get(hir_id) {
-            hir::Node::Block(blk) => self.find_block_span(blk),
-            // The parser was in a weird state if either of these happen, but
-            // it's better not to panic.
-            hir::Node::Expr(e) => e.span,
-            _ => rustc_span::DUMMY_SP,
-        }
-    }
-}
index a130fde47ed5c4d7c0ccdae1536387b649f7cc1b..749e960bfd03090876186167b6b6247b5eb44efc 100644 (file)
@@ -61,7 +61,7 @@ pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
                 .as_local()
                 .map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some())
         };
-        let value = value.fold_with(&mut ty::fold::BottomUpFolder {
+        let value = value.fold_with(&mut BottomUpFolder {
             tcx: self.tcx,
             lt_op: |lt| lt,
             ct_op: |ct| ct,
index 47bd1564f0828ab1a36cb97f74d81b3f05143128..a85e6a19b11b65b99fdc279a195f5822cd3a4220 100644 (file)
@@ -60,7 +60,6 @@
 //! imply that `'b: 'a`.
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::outlives::verify::VerifyBoundCx;
 use crate::infer::{
@@ -68,9 +67,7 @@
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
-use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
@@ -116,7 +113,7 @@ pub fn take_registered_region_obligations(&self) -> Vec<RegionObligation<'tcx>>
         std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
-    /// NOTE: Prefer using [`InferCtxt::check_region_obligations_and_report_errors`]
+    /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
     /// instead of calling this directly.
     ///
     /// Process the region obligations that must be proven (during
@@ -170,22 +167,6 @@ pub fn process_registered_region_obligations(
             outlives.type_must_outlive(origin, sup_type, sub_region, category);
         }
     }
-
-    /// Processes registered region obliations and resolves regions, reporting
-    /// any errors if any were raised. Prefer using this function over manually
-    /// calling `resolve_regions_and_report_errors`.
-    pub fn check_region_obligations_and_report_errors(
-        &self,
-        generic_param_scope: LocalDefId,
-        outlives_env: &OutlivesEnvironment<'tcx>,
-    ) -> Option<ErrorGuaranteed> {
-        self.process_registered_region_obligations(
-            outlives_env.region_bound_pairs(),
-            outlives_env.param_env,
-        );
-
-        self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
-    }
 }
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
index 76442de69d35147d7d7634c14d25e2cbef4dcf1b..ee0552d77ceee8080eab5dd43ed6f63f115a2e9f 100644 (file)
@@ -10,6 +10,7 @@
 //! origin crate when the `TyCtxt` is not present in TLS.
 
 use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
+use rustc_middle::dep_graph::TaskDepsRef;
 use rustc_middle::ty::tls;
 use std::fmt;
 
@@ -26,14 +27,22 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
 /// This is a callback from `rustc_ast` as it cannot access the implicit state
 /// in `rustc_middle` otherwise. It is used when diagnostic messages are
 /// emitted and stores them in the current query, if there is one.
-fn track_diagnostic(diagnostic: &Diagnostic) {
+fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
     tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
             if let Some(diagnostics) = icx.diagnostics {
                 let mut diagnostics = diagnostics.lock();
                 diagnostics.extend(Some(diagnostic.clone()));
+                std::mem::drop(diagnostics);
             }
+
+            // Diagnostics are tracked, we can ignore the dependency.
+            let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
+            return tls::enter_context(&icx, move |_| (*f)(diagnostic));
         }
+
+        // In any other case, invoke diagnostics anyway.
+        (*f)(diagnostic);
     })
 }
 
@@ -55,5 +64,5 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
 pub fn setup_callbacks() {
     rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
     rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
-    TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
+    TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
 }
index 4c22ab68a5681f227aa4a644c64a346be1689311..7f761b005edd0946ce8e406282fa529f899268a5 100644 (file)
@@ -90,8 +90,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
             .into_iter()
             .map(|s| {
                 let sess = ParseSess::with_silent_emitter(Some(format!(
-                    "this error occurred on the command line: `--cfg={}`",
-                    s
+                    "this error occurred on the command line: `--cfg={s}`"
                 )));
                 let filename = FileName::cfg_spec_source_code(&s);
 
@@ -150,8 +149,7 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
 
         'specs: for s in specs {
             let sess = ParseSess::with_silent_emitter(Some(format!(
-                "this error occurred on the command line: `--check-cfg={}`",
-                s
+                "this error occurred on the command line: `--check-cfg={s}`"
             )));
             let filename = FileName::cfg_spec_source_code(&s);
 
index 89d9450cf4e89a0b6335647b5bf5f2446f7207bd..86d56385bc9630486eed68198343e07741555ae0 100644 (file)
@@ -620,7 +620,7 @@ fn write_out_deps(
         // prevents `make` from spitting out an error if a file is later
         // deleted. For more info see #28735
         for path in files {
-            writeln!(file, "{}:", path)?;
+            writeln!(file, "{path}:")?;
         }
 
         // Emit special comments with information about accessed environment variables.
@@ -633,9 +633,9 @@ fn write_out_deps(
             envs.sort_unstable();
             writeln!(file)?;
             for (k, v) in envs {
-                write!(file, "# env-dep:{}", k)?;
+                write!(file, "# env-dep:{k}")?;
                 if let Some(v) = v {
-                    write!(file, "={}", v)?;
+                    write!(file, "={v}")?;
                 }
                 writeln!(file)?;
             }
index ff2196d58577c817557e23d497733fbbc7c00f2e..316e2e29cd8b31c107aaed69dcc00f04bb232e50 100644 (file)
@@ -3,17 +3,17 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
-use rustc_session::config::InstrumentCoverage;
-use rustc_session::config::Strip;
+use rustc_session::config::rustc_optgroups;
+use rustc_session::config::TraitSolver;
 use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
-use rustc_session::config::{
-    rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
-};
 use rustc_session::config::{
     BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
     ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
 };
 use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
+use rustc_session::config::{DumpMonoStatsFormat, MirSpanview};
+use rustc_session::config::{ErrorOutputType, ExternLocation, LocationDetail, Options, Strip};
+use rustc_session::config::{InstrumentCoverage, Passes};
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
@@ -647,12 +647,14 @@ macro_rules! untracked {
     untracked!(dump_mir_dir, String::from("abc"));
     untracked!(dump_mir_exclude_pass_number, true);
     untracked!(dump_mir_graphviz, true);
+    untracked!(dump_mir_spanview, Some(MirSpanview::Statement));
+    untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into())));
+    untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json);
     untracked!(dylib_lto, true);
     untracked!(emit_stack_sizes, true);
     untracked!(future_incompat_test, true);
     untracked!(hir_stats, true);
     untracked!(identify_regions, true);
-    untracked!(incremental_ignore_spans, true);
     untracked!(incremental_info, true);
     untracked!(incremental_verify_ich, true);
     untracked!(input_stats, true);
@@ -721,7 +723,6 @@ macro_rules! tracked {
             pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B })
         })
     );
-    tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(debug_info_for_profiling, true);
@@ -737,6 +738,7 @@ macro_rules! tracked {
     tracked!(fuel, Some(("abc".to_string(), 99)));
     tracked!(function_sections, Some(false));
     tracked!(human_readable_cgu_names, true);
+    tracked!(incremental_ignore_spans, true);
     tracked!(inline_in_all_cgus, Some(true));
     tracked!(inline_mir, Some(true));
     tracked!(inline_mir_hint_threshold, Some(123));
@@ -790,6 +792,7 @@ macro_rules! tracked {
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
+    tracked!(trait_solver, TraitSolver::Chalk);
     tracked!(translate_remapped_path_to_local_path, false);
     tracked!(trap_unreachable, Some(false));
     tracked!(treat_err_as_bug, NonZeroUsize::new(1));
index 4142964a0dabbcd6905ed08c9e828ce9e7d3b7f7..02a7756c8d4532077cde69573a8c3e49c1b6ba76 100644 (file)
@@ -205,13 +205,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
 
 fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
     let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
-        let err = format!("couldn't load codegen backend {:?}: {}", path, err);
+        let err = format!("couldn't load codegen backend {path:?}: {err}");
         early_error(ErrorOutputType::default(), &err);
     });
 
     let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
         .unwrap_or_else(|e| {
-            let err = format!("couldn't load codegen backend: {}", e);
+            let err = format!("couldn't load codegen backend: {e}");
             early_error(ErrorOutputType::default(), &err);
         });
 
@@ -304,8 +304,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
             .join("\n* ");
         let err = format!(
             "failed to find a `codegen-backends` folder \
-                           in the sysroot candidates:\n* {}",
-            candidates
+                           in the sysroot candidates:\n* {candidates}"
         );
         early_error(ErrorOutputType::default(), &err);
     });
@@ -325,7 +324,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
 
     let expected_names = &[
         format!("rustc_codegen_{}-{}", backend_name, env!("CFG_RELEASE")),
-        format!("rustc_codegen_{}", backend_name),
+        format!("rustc_codegen_{backend_name}"),
     ];
     for entry in d.filter_map(|e| e.ok()) {
         let path = entry.path();
@@ -354,7 +353,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
     match file {
         Some(ref s) => load_backend_from_dylib(s),
         None => {
-            let err = format!("unsupported builtin codegen backend `{}`", backend_name);
+            let err = format!("unsupported builtin codegen backend `{backend_name}`");
             early_error(ErrorOutputType::default(), &err);
         }
     }
@@ -389,7 +388,7 @@ pub(crate) fn check_attr_crate_type(
                             BuiltinLintDiagnostics::UnknownCrateTypes(
                                 span,
                                 "did you mean".to_string(),
-                                format!("\"{}\"", candidate),
+                                format!("\"{candidate}\""),
                             ),
                         );
                     } else {
index 50d6d5b9bab91a0bc08807c708ad7f02858d2842..4c65fca29b89721542148dcfadf447bee9f7048b 100644 (file)
@@ -851,7 +851,7 @@ fn eat_literal_suffix(&mut self) {
     }
 
     // Eats the identifier. Note: succeeds on `_`, which isn't a valid
-    // identifer.
+    // identifier.
     fn eat_identifier(&mut self) {
         if !is_id_start(self.first()) {
             return;
index d6de6e70ead808a888d8a56a611a424c3f36e2f4..d58168ff37721d71cde3c8b28a271f79920a2fe6 100644 (file)
@@ -1392,7 +1392,7 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
     ///
     /// The attribute must be used in conjunction with the
     /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]`
-    /// annotation will function as as no-op.
+    /// annotation will function as a no-op.
     ///
     /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html
     UNGATED_ASYNC_FN_TRACK_CALLER,
@@ -1526,7 +1526,7 @@ fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::Forei
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
         let map = cx.tcx.hir();
-        if matches!(map.get(map.get_parent_node(field.hir_id)), Node::Variant(_)) {
+        if matches!(map.get_parent(field.hir_id), Node::Variant(_)) {
             return;
         }
         self.perform_lint(cx, "field", field.def_id, field.vis_span, false);
@@ -2184,6 +2184,7 @@ fn collect_outlives_bound_spans<'tcx>(
         tcx: TyCtxt<'tcx>,
         bounds: &hir::GenericBounds<'_>,
         inferred_outlives: &[ty::Region<'tcx>],
+        predicate_span: Span,
     ) -> Vec<(usize, Span)> {
         use rustc_middle::middle::resolve_lifetime::Region;
 
@@ -2191,23 +2192,28 @@ fn collect_outlives_bound_spans<'tcx>(
             .iter()
             .enumerate()
             .filter_map(|(i, bound)| {
-                if let hir::GenericBound::Outlives(lifetime) = bound {
-                    let is_inferred = match tcx.named_region(lifetime.hir_id) {
-                        Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
-                            if let ty::ReEarlyBound(ebr) = **r {
-                                ebr.def_id == def_id
-                            } else {
-                                false
-                            }
-                        }),
-                        _ => false,
-                    };
-                    is_inferred.then_some((i, bound.span()))
-                } else {
-                    None
+                let hir::GenericBound::Outlives(lifetime) = bound else {
+                    return None;
+                };
+
+                let is_inferred = match tcx.named_region(lifetime.hir_id) {
+                    Some(Region::EarlyBound(def_id)) => inferred_outlives
+                        .iter()
+                        .any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })),
+                    _ => false,
+                };
+
+                if !is_inferred {
+                    return None;
                 }
+
+                let span = bound.span().find_ancestor_inside(predicate_span)?;
+                if in_external_macro(tcx.sess, span) {
+                    return None;
+                }
+
+                Some((i, span))
             })
-            .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
             .collect()
     }
 
@@ -2273,9 +2279,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         use rustc_middle::middle::resolve_lifetime::Region;
 
         let def_id = item.owner_id.def_id;
-        if let hir::ItemKind::Struct(_, ref hir_generics)
-        | hir::ItemKind::Enum(_, ref hir_generics)
-        | hir::ItemKind::Union(_, ref hir_generics) = item.kind
+        if let hir::ItemKind::Struct(_, hir_generics)
+        | hir::ItemKind::Enum(_, hir_generics)
+        | hir::ItemKind::Union(_, hir_generics) = item.kind
         {
             let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
             if inferred_outlives.is_empty() {
@@ -2290,53 +2296,58 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
             let mut dropped_predicate_count = 0;
             let num_predicates = hir_generics.predicates.len();
             for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
-                let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
-                    hir::WherePredicate::RegionPredicate(predicate) => {
-                        if let Some(Region::EarlyBound(region_def_id)) =
-                            cx.tcx.named_region(predicate.lifetime.hir_id)
-                        {
-                            (
-                                Self::lifetimes_outliving_lifetime(
-                                    inferred_outlives,
-                                    region_def_id,
-                                ),
-                                &predicate.bounds,
-                                predicate.span,
-                                predicate.in_where_clause,
-                            )
-                        } else {
-                            continue;
-                        }
-                    }
-                    hir::WherePredicate::BoundPredicate(predicate) => {
-                        // FIXME we can also infer bounds on associated types,
-                        // and should check for them here.
-                        match predicate.bounded_ty.kind {
-                            hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
-                                let Res::Def(DefKind::TyParam, def_id) = path.res else {
-                                    continue
-                                };
-                                let index = ty_generics.param_def_id_to_index[&def_id];
+                let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
+                    match where_predicate {
+                        hir::WherePredicate::RegionPredicate(predicate) => {
+                            if let Some(Region::EarlyBound(region_def_id)) =
+                                cx.tcx.named_region(predicate.lifetime.hir_id)
+                            {
                                 (
-                                    Self::lifetimes_outliving_type(inferred_outlives, index),
+                                    Self::lifetimes_outliving_lifetime(
+                                        inferred_outlives,
+                                        region_def_id,
+                                    ),
                                     &predicate.bounds,
                                     predicate.span,
-                                    predicate.origin == PredicateOrigin::WhereClause,
+                                    predicate.in_where_clause,
                                 )
-                            }
-                            _ => {
+                            } else {
                                 continue;
                             }
                         }
-                    }
-                    _ => continue,
-                };
+                        hir::WherePredicate::BoundPredicate(predicate) => {
+                            // FIXME we can also infer bounds on associated types,
+                            // and should check for them here.
+                            match predicate.bounded_ty.kind {
+                                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
+                                    let Res::Def(DefKind::TyParam, def_id) = path.res else {
+                                    continue;
+                                };
+                                    let index = ty_generics.param_def_id_to_index[&def_id];
+                                    (
+                                        Self::lifetimes_outliving_type(inferred_outlives, index),
+                                        &predicate.bounds,
+                                        predicate.span,
+                                        predicate.origin == PredicateOrigin::WhereClause,
+                                    )
+                                }
+                                _ => {
+                                    continue;
+                                }
+                            }
+                        }
+                        _ => continue,
+                    };
                 if relevant_lifetimes.is_empty() {
                     continue;
                 }
 
-                let bound_spans =
-                    self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
+                let bound_spans = self.collect_outlives_bound_spans(
+                    cx.tcx,
+                    bounds,
+                    &relevant_lifetimes,
+                    predicate_span,
+                );
                 bound_count += bound_spans.len();
 
                 let drop_predicate = bound_spans.len() == bounds.len();
@@ -2345,15 +2356,15 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                 }
 
                 if drop_predicate && !in_where_clause {
-                    lint_spans.push(span);
+                    lint_spans.push(predicate_span);
                 } else if drop_predicate && i + 1 < num_predicates {
                     // If all the bounds on a predicate were inferable and there are
                     // further predicates, we want to eat the trailing comma.
                     let next_predicate_span = hir_generics.predicates[i + 1].span();
-                    where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
+                    where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo()));
                 } else {
                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
-                        span.shrink_to_lo(),
+                        predicate_span.shrink_to_lo(),
                         bounds,
                         bound_spans,
                     ));
@@ -2374,12 +2385,26 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     } else {
                         hir_generics.span.shrink_to_hi().to(where_span)
                     };
-                lint_spans.push(full_where_span);
+
+                // Due to macro expansions, the `full_where_span` might not actually contain all predicates.
+                if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) {
+                    lint_spans.push(full_where_span);
+                } else {
+                    lint_spans.extend(where_lint_spans);
+                }
             } else {
                 lint_spans.extend(where_lint_spans);
             }
 
             if !lint_spans.is_empty() {
+                // Do not automatically delete outlives requirements from macros.
+                let applicability = if lint_spans.iter().all(|sp| sp.can_be_used_for_suggestions())
+                {
+                    Applicability::MachineApplicable
+                } else {
+                    Applicability::MaybeIncorrect
+                };
+
                 cx.struct_span_lint(
                     EXPLICIT_OUTLIVES_REQUIREMENTS,
                     lint_spans.clone(),
@@ -2387,11 +2412,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     |lint| {
                         lint.set_arg("count", bound_count).multipart_suggestion(
                             fluent::suggestion,
-                            lint_spans
-                                .into_iter()
-                                .map(|span| (span, String::new()))
-                                .collect::<Vec<_>>(),
-                            Applicability::MachineApplicable,
+                            lint_spans.into_iter().map(|span| (span, String::new())).collect(),
+                            applicability,
                         )
                     },
                 );
index 5f84d5c8b949575394d401a287bbe1b025563376..c18abaef8e2565e450bffb1959adfdf5dde7532b 100644 (file)
@@ -29,7 +29,7 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-/// Implements the AST traversal for early lint passes. `T` provides the the
+/// Implements the AST traversal for early lint passes. `T` provides the
 /// `check_*` methods.
 pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
     context: EarlyContext<'a>,
index 4f92661dbd3342198d286c717b67a26bd7039bf6..48902cd05695c751a1c1173fdbe4f2f7f571eaa1 100644 (file)
@@ -143,7 +143,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
             TyKind::Path(QPath::Resolved(_, path)) => {
                 if lint_ty_kind_usage(cx, &path.res) {
                     let hir = cx.tcx.hir();
-                    let span = match hir.find(hir.get_parent_node(ty.hir_id)) {
+                    let span = match hir.find_parent(ty.hir_id) {
                         Some(Node::Pat(Pat {
                             kind:
                                 PatKind::Path(qpath)
index e2876938d70566477329cc94541c81478a3894f1..b2a2656746eec8b45849ec4faf9ce905ef15ec69 100644 (file)
@@ -40,7 +40,7 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-/// Implements the AST traversal for late lint passes. `T` provides the the
+/// Implements the AST traversal for late lint passes. `T` provides the
 /// `check_*` methods.
 pub struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
     context: LateContext<'tcx>,
index 91fcd6d690ee7a52c819546eccc065dca1baf64c..f37d6e9a63d49f076c7ece809256944a18d6067d 100644 (file)
@@ -444,8 +444,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &hir::TraitItem<'_>)
 
     fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
         if let PatKind::Binding(_, hid, ident, _) = p.kind {
-            if let hir::Node::PatField(field) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
-            {
+            if let hir::Node::PatField(field) = cx.tcx.hir().get_parent(hid) {
                 if !field.is_shorthand {
                     // Only check if a new name has been introduced, to avoid warning
                     // on both the struct definition and this pattern.
index 0fa81b7e4e0bc20f2c644783199734475e474359..22caadfab177d40b087c2ecee4433eaa078809a8 100644 (file)
@@ -22,7 +22,7 @@
 impl<'tcx> LateLintPass<'tcx> for PassByValue {
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
         match &ty.kind {
-            TyKind::Rptr(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
+            TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
                 if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
                     if cx.tcx.impl_trait_ref(impl_did).is_some() {
                         return;
index 8e27bc03c489aeedf8ab0b5d2cd15776c8cff157..fa415243ba066c99cc897973023aebff1ddd2479 100644 (file)
@@ -127,10 +127,9 @@ fn lint_overflowing_range_endpoint<'tcx>(
 ) -> bool {
     // We only want to handle exclusive (`..`) ranges,
     // which are represented as `ExprKind::Struct`.
-    let par_id = cx.tcx.hir().get_parent_node(expr.hir_id);
+    let par_id = cx.tcx.hir().parent_id(expr.hir_id);
     let Node::ExprField(field) = cx.tcx.hir().get(par_id) else { return false };
-    let field_par_id = cx.tcx.hir().get_parent_node(field.hir_id);
-    let Node::Expr(struct_expr) = cx.tcx.hir().get(field_par_id) else { return false };
+    let Node::Expr(struct_expr) = cx.tcx.hir().get_parent(field.hir_id) else { return false };
     if !is_range_literal(struct_expr) {
         return false;
     };
@@ -404,7 +403,7 @@ fn lint_uint_literal<'tcx>(
         _ => bug!(),
     };
     if lit_val < min || lit_val > max {
-        let parent_id = cx.tcx.hir().get_parent_node(e.hir_id);
+        let parent_id = cx.tcx.hir().parent_id(e.hir_id);
         if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) {
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
index 3b8df61a0eab771a704f9ed9006bbd1807b612fa..525079681ca5cec4eee3f16787df9760519508df 100644 (file)
@@ -256,7 +256,7 @@ fn is_ty_must_use<'tcx>(
                         cx.tcx,
                         cx.tcx.explicit_item_bounds(def).iter().cloned(),
                     )
-                    .filter_map(|obligation| {
+                    .find_map(|obligation| {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateKind::Clause(ty::Clause::Trait(
                             ref poly_trait_predicate,
@@ -270,22 +270,17 @@ fn is_ty_must_use<'tcx>(
                         }
                     })
                     .map(|inner| MustUsePath::Opaque(Box::new(inner)))
-                    .next()
                 }
-                ty::Dynamic(binders, _, _) => binders
-                    .iter()
-                    .filter_map(|predicate| {
-                        if let ty::ExistentialPredicate::Trait(ref trait_ref) =
-                            predicate.skip_binder()
-                        {
-                            let def_id = trait_ref.def_id;
-                            is_def_must_use(cx, def_id, span)
-                        } else {
-                            None
-                        }
-                        .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
-                    })
-                    .next(),
+                ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
+                    if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
+                    {
+                        let def_id = trait_ref.def_id;
+                        is_def_must_use(cx, def_id, span)
+                            .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
+                    } else {
+                        None
+                    }
+                }),
                 ty::Tuple(tys) => {
                     let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
                         debug_assert_eq!(elem_exprs.len(), tys.len());
@@ -1142,6 +1137,7 @@ fn check_unused_delims_expr(
                             && !cx.sess().source_map().is_multiline(value.span)
                             && value.attrs.is_empty()
                             && !value.span.from_expansion()
+                            && !inner.span.from_expansion()
                         {
                             self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
                         }
index 0b3c057345a67d9a532e4b15e041f353b88f1743..9fe59a1d8261b15a2871dddd3a9015ca5ef6e92c 100644 (file)
@@ -58,7 +58,7 @@ fn restore_library_path() {
 /// Supposed to be used for all variables except those set for build scripts by cargo
 /// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
 fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
-    println!("cargo:rerun-if-env-changed={}", key);
+    println!("cargo:rerun-if-env-changed={key}");
     env::var_os(key)
 }
 
@@ -84,7 +84,7 @@ fn output(cmd: &mut Command) -> String {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
         Err(e) => {
-            println!("\n\nfailed to execute command: {:?}\nerror: {}\n\n", cmd, e);
+            println!("\n\nfailed to execute command: {cmd:?}\nerror: {e}\n\n");
             std::process::exit(1);
         }
     };
@@ -100,7 +100,7 @@ fn output(cmd: &mut Command) -> String {
 
 fn main() {
     for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) {
-        println!("cargo:rustc-check-cfg=values(llvm_component,\"{}\")", component);
+        println!("cargo:rustc-check-cfg=values(llvm_component,\"{component}\")");
     }
 
     if tracked_env_var_os("RUST_CHECK").is_some() {
@@ -164,12 +164,12 @@ fn main() {
 
     for component in REQUIRED_COMPONENTS {
         if !components.contains(component) {
-            panic!("require llvm component {} but wasn't found", component);
+            panic!("require llvm component {component} but wasn't found");
         }
     }
 
     for component in components.iter() {
-        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
+        println!("cargo:rustc-cfg=llvm_component=\"{component}\"");
     }
 
     // Link in our own LLVM shims, compiled with the same flags as LLVM
@@ -283,7 +283,7 @@ fn main() {
         }
 
         let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
-        println!("cargo:rustc-link-lib={}={}", kind, name);
+        println!("cargo:rustc-link-lib={kind}={name}");
     }
 
     // LLVM ldflags
@@ -302,11 +302,11 @@ fn main() {
                 println!("cargo:rustc-link-search=native={}", stripped.replace(&host, &target));
             }
         } else if let Some(stripped) = lib.strip_prefix("-LIBPATH:") {
-            println!("cargo:rustc-link-search=native={}", stripped);
+            println!("cargo:rustc-link-search=native={stripped}");
         } else if let Some(stripped) = lib.strip_prefix("-l") {
-            println!("cargo:rustc-link-lib={}", stripped);
+            println!("cargo:rustc-link-lib={stripped}");
         } else if let Some(stripped) = lib.strip_prefix("-L") {
-            println!("cargo:rustc-link-search=native={}", stripped);
+            println!("cargo:rustc-link-search=native={stripped}");
         }
     }
 
@@ -318,9 +318,9 @@ fn main() {
     if let Some(s) = llvm_linker_flags {
         for lib in s.into_string().unwrap().split_whitespace() {
             if let Some(stripped) = lib.strip_prefix("-l") {
-                println!("cargo:rustc-link-lib={}", stripped);
+                println!("cargo:rustc-link-lib={stripped}");
             } else if let Some(stripped) = lib.strip_prefix("-L") {
-                println!("cargo:rustc-link-search=native={}", stripped);
+                println!("cargo:rustc-link-search=native={stripped}");
             }
         }
     }
@@ -359,14 +359,14 @@ fn main() {
             let path = PathBuf::from(s);
             println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
             if target.contains("windows") {
-                println!("cargo:rustc-link-lib=static:-bundle={}", stdcppname);
+                println!("cargo:rustc-link-lib=static:-bundle={stdcppname}");
             } else {
-                println!("cargo:rustc-link-lib=static={}", stdcppname);
+                println!("cargo:rustc-link-lib=static={stdcppname}");
             }
         } else if cxxflags.contains("stdlib=libc++") {
             println!("cargo:rustc-link-lib=c++");
         } else {
-            println!("cargo:rustc-link-lib={}", stdcppname);
+            println!("cargo:rustc-link-lib={stdcppname}");
         }
     }
 
index ddf29c488c933284433fd2f63376c2d7367e28cf..4cac88aff640e66dff6b89b5ac1feaca2f95bec7 100644 (file)
@@ -114,8 +114,7 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Error::InvalidColorValue(value) => write!(
                 formatter,
-                "invalid log color value '{}': expected one of always, never, or auto",
-                value,
+                "invalid log color value '{value}': expected one of always, never, or auto",
             ),
             Error::NonUnicodeColorValue => write!(
                 formatter,
index 4612f54e4b17639292af0024191668a74d41f922..2d62d59316387695b2152d48a6e3ae45c9dad0c7 100644 (file)
@@ -76,11 +76,11 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
     let span = attr.span().unwrap();
     let path = path_to_string(&attr.path);
     match meta {
-        Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", path)),
+        Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")),
         Meta::NameValue(_) => {
-            span_err(span, &format!("`#[{} = ...]` is not a valid attribute", path))
+            span_err(span, &format!("`#[{path} = ...]` is not a valid attribute"))
         }
-        Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", path)),
+        Meta::List(_) => span_err(span, &format!("`#[{path}(...)]` is not a valid attribute")),
     }
 }
 
@@ -107,7 +107,7 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag
     let meta = match nested {
         syn::NestedMeta::Meta(meta) => meta,
         syn::NestedMeta::Lit(_) => {
-            return span_err(span, &format!("`#[{}(\"...\")]` is not a valid attribute", name));
+            return span_err(span, &format!("`#[{name}(\"...\")]` is not a valid attribute"));
         }
     };
 
@@ -115,13 +115,11 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag
     let path = path_to_string(meta.path());
     match meta {
         Meta::NameValue(..) => {
-            span_err(span, &format!("`#[{}({} = ...)]` is not a valid attribute", name, path))
-        }
-        Meta::Path(..) => {
-            span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, path))
+            span_err(span, &format!("`#[{name}({path} = ...)]` is not a valid attribute"))
         }
+        Meta::Path(..) => span_err(span, &format!("`#[{name}({path})]` is not a valid attribute")),
         Meta::List(..) => {
-            span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, path))
+            span_err(span, &format!("`#[{name}({path}(...))]` is not a valid attribute"))
         }
     }
 }
index 3e447c94ef1238d3d977356d6ea70e8f3ce9fe3d..32338f9dfc5e3893c833eb754769309379b6f1e9 100644 (file)
@@ -178,7 +178,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                         opt: Default::default(),
                     };
                     let dl = DisplayList::from(snippet);
-                    eprintln!("{}\n", dl);
+                    eprintln!("{dl}\n");
                 }
                 continue;
             }
@@ -265,7 +265,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                         Diagnostic::spanned(
                             path_span,
                             Level::Error,
-                            format!("overrides existing {}: `{}`", kind, id),
+                            format!("overrides existing {kind}: `{id}`"),
                         )
                         .span_help(previous_defns[&id], "previously defined in this resource")
                         .emit();
index 767db3673225988f7bbe02621bfab31cb76b56db..baffd3cec9c55394dfea79608bb7c3fe840e04c9 100644 (file)
@@ -198,8 +198,7 @@ fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, Diagnostic
                 throw_span_err!(
                     attr.span().unwrap(),
                     &format!(
-                        "diagnostic slug must be first argument of a `#[{}(...)]` attribute",
-                        name
+                        "diagnostic slug must be first argument of a `#[{name}(...)]` attribute"
                     )
                 );
             };
index 4ff9c777ad8587215548ecff47ff104733d0b9e0..6f52a3de1b151ad26c833937addc22fd38753038 100644 (file)
@@ -322,7 +322,7 @@ fn build_format(&self, input: &str, span: proc_macro2::Span) -> TokenStream {
                 None => {
                     span_err(
                         span.unwrap(),
-                        &format!("`{}` doesn't refer to a field on this type", field),
+                        &format!("`{field}` doesn't refer to a field on this type"),
                     )
                     .emit();
                     quote! {
@@ -603,8 +603,7 @@ pub(super) fn from_attr(
                     if suggestion_kind != SuggestionKind::Normal {
                         invalid_attr(attr, &meta)
                             .help(format!(
-                                r#"Use `#[suggestion(..., style = "{}")]` instead"#,
-                                suggestion_kind
+                                r#"Use `#[suggestion(..., style = "{suggestion_kind}")]` instead"#
                             ))
                             .emit();
                     }
@@ -621,8 +620,7 @@ pub(super) fn from_attr(
                     if suggestion_kind != SuggestionKind::Normal {
                         invalid_attr(attr, &meta)
                             .help(format!(
-                                r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"#,
-                                suggestion_kind
+                                r#"Use `#[multipart_suggestion(..., style = "{suggestion_kind}")]` instead"#
                             ))
                             .emit();
                     }
index 153473de6244952770385d1f5233ac4106a17168..89ea89cf502e5e4c2723be0c371b2794c2ff84db 100644 (file)
@@ -41,7 +41,7 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
                     };
 
                     if let Some(old) = max.replace(literal.lit) {
-                        panic!("Specified multiple max: {:?}", old);
+                        panic!("Specified multiple max: {old:?}");
                     }
 
                     false
@@ -52,7 +52,7 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
                     };
 
                     if let Some(old) = debug_format.replace(literal.lit) {
-                        panic!("Specified multiple debug format options: {:?}", old);
+                        panic!("Specified multiple debug format options: {old:?}");
                     }
 
                     false
index 789d83a0dd00d496f39eeee157d924d6f3cfd31b..08e42a8a08f92b469ec6f1c64258351c9d0a1889 100644 (file)
@@ -239,7 +239,7 @@ fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attrib
             .unwrap();
         },
     );
-    let doc_string = format!("[query description - consider adding a doc-comment!] {}", doc_string);
+    let doc_string = format!("[query description - consider adding a doc-comment!] {doc_string}");
     Ok(parse_quote! { #[doc = #doc_string] })
 }
 
index 92590c33b9d1e90b765492e3894a35854d7f6c80..04facbf657d225d0b7c3bb9bcf62b6acaaaab691 100644 (file)
@@ -134,7 +134,7 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
 
     let mut check_dup = |span: Span, str: &str, errors: &mut Errors| {
         if let Some(prev_span) = keys.get(str) {
-            errors.error(span, format!("Symbol `{}` is duplicated", str));
+            errors.error(span, format!("Symbol `{str}` is duplicated"));
             errors.error(*prev_span, "location of previous definition".to_string());
         } else {
             keys.insert(str.to_string(), span);
@@ -144,8 +144,8 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
     let mut check_order = |span: Span, str: &str, errors: &mut Errors| {
         if let Some((prev_span, ref prev_str)) = prev_key {
             if str < prev_str {
-                errors.error(span, format!("Symbol `{}` must precede `{}`", str, prev_str));
-                errors.error(prev_span, format!("location of previous symbol `{}`", prev_str));
+                errors.error(span, format!("Symbol `{str}` must precede `{prev_str}`"));
+                errors.error(prev_span, format!("location of previous symbol `{prev_str}`"));
             }
         }
         prev_key = Some((span, str.to_string()));
index 842d2a977189d53e6a7e0102ef8a9e7e9823cd57..bd0c08a53c4f20eb2ce5b6a15a561091ce83d0a6 100644 (file)
@@ -16,14 +16,13 @@ fn test_symbols() {
     let m: &syn::ItemMacro = file
         .items
         .iter()
-        .filter_map(|i| {
+        .find_map(|i| {
             if let syn::Item::Macro(m) = i {
                 if m.mac.path == symbols_path { Some(m) } else { None }
             } else {
                 None
             }
         })
-        .next()
         .expect("did not find `symbols!` macro invocation.");
 
     let body_tokens = m.mac.tokens.clone();
index b34dc0df1e2805702763fc4ce09a53a677308022..653f2b39d3e74f646e22b01133ff4afe25f29bf4 100644 (file)
@@ -112,7 +112,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         writeln!(fmt, "resolved crates:")?;
         for (cnum, data) in self.0.iter_crate_data() {
             writeln!(fmt, "  name: {}", data.name())?;
-            writeln!(fmt, "  cnum: {}", cnum)?;
+            writeln!(fmt, "  cnum: {cnum}")?;
             writeln!(fmt, "  hash: {}", data.hash())?;
             writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
             let CrateSource { dylib, rlib, rmeta } = data.source();
@@ -150,7 +150,7 @@ pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
     pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
         let cdata = self.metas[cnum]
             .as_ref()
-            .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum));
+            .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"));
         CrateMetadataRef { cdata, cstore: self }
     }
 
index 6112ec9e4e948b6b8d01068f57336c7f83d84067..cee4ba56a9d8f863180eefcb1c3bb4e7745ae23c 100644 (file)
@@ -54,7 +54,7 @@
 use crate::creader::CStore;
 use crate::errors::{
     BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
-    RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+    RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -224,7 +224,12 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                     Linkage::Static => "rlib",
                     _ => "dylib",
                 };
-                sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
+                let crate_name = tcx.crate_name(cnum);
+                if crate_name.as_str().starts_with("rustc_") {
+                    sess.emit_err(RustcLibRequired { crate_name, kind });
+                } else {
+                    sess.emit_err(LibRequired { crate_name, kind });
+                }
             }
         }
     }
index de2a879f1d73769c59f4dda5661f1abc93e1b5cf..02c03114eb67f637cf5b1236e0d25d1310239019 100644 (file)
@@ -24,6 +24,14 @@ pub struct LibRequired<'a> {
     pub kind: &'a str,
 }
 
+#[derive(Diagnostic)]
+#[diag(metadata_rustc_lib_required)]
+#[help]
+pub struct RustcLibRequired<'a> {
+    pub crate_name: Symbol,
+    pub kind: &'a str,
+}
+
 #[derive(Diagnostic)]
 #[diag(metadata_crate_dep_multiple)]
 #[help]
@@ -486,25 +494,15 @@ fn into_diagnostic(
         let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("flavor", self.flavor);
-        diag.code(error_code!(E0465));
+        diag.code(error_code!(E0464));
         diag.set_span(self.span);
         for (i, candidate) in self.candidates.iter().enumerate() {
-            diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+            diag.note(&format!("candidate #{}: {}", i + 1, candidate.display()));
         }
         diag
     }
 }
 
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_matching_crates, code = "E0464")]
-#[note]
-pub struct MultipleMatchingCrates {
-    #[primary_span]
-    pub span: Span,
-    pub crate_name: Symbol,
-    pub candidates: String,
-}
-
 #[derive(Diagnostic)]
 #[diag(metadata_symbol_conflicts_current, code = "E0519")]
 pub struct SymbolConflictsCurrent {
index dda5f4bac4289310140abef18ff316f57bf44132..92dc5bd41cbab45ae3ac84031c10d63b2f0b01c9 100644 (file)
 use crate::errors::{
     CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist,
     ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles,
-    LibFilenameForm, MultipleCandidates, MultipleMatchingCrates, NewerCrateVersion,
-    NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent,
-    SymbolConflictsOthers,
+    LibFilenameForm, MultipleCandidates, NewerCrateVersion, NoCrateWithTriple, NoDylibPlugin,
+    NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent, SymbolConflictsOthers,
 };
 use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 
 use snap::read::FrameDecoder;
 use std::borrow::Cow;
-use std::fmt::Write as _;
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt, fs};
@@ -482,7 +480,22 @@ fn find_library_crate(
         match libraries.len() {
             0 => Ok(None),
             1 => Ok(Some(libraries.into_iter().next().unwrap().1)),
-            _ => Err(CrateError::MultipleMatchingCrates(self.crate_name, libraries)),
+            _ => {
+                let mut libraries: Vec<_> = libraries.into_values().collect();
+
+                libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
+                let candidates = libraries
+                    .iter()
+                    .map(|lib| lib.source.paths().next().unwrap().clone())
+                    .collect::<Vec<_>>();
+
+                Err(CrateError::MultipleCandidates(
+                    self.crate_name,
+                    // these are the same for all candidates
+                    get_flavor_from_path(candidates.first().unwrap()),
+                    candidates,
+                ))
+            }
         }
     }
 
@@ -882,17 +895,22 @@ pub fn list_file_metadata(
     metadata_loader: &dyn MetadataLoader,
     out: &mut dyn Write,
 ) -> IoResult<()> {
+    let flavor = get_flavor_from_path(path);
+    match get_metadata_section(target, flavor, path, metadata_loader) {
+        Ok(metadata) => metadata.list_crate_metadata(out),
+        Err(msg) => write!(out, "{}\n", msg),
+    }
+}
+
+fn get_flavor_from_path(path: &Path) -> CrateFlavor {
     let filename = path.file_name().unwrap().to_str().unwrap();
-    let flavor = if filename.ends_with(".rlib") {
+
+    if filename.ends_with(".rlib") {
         CrateFlavor::Rlib
     } else if filename.ends_with(".rmeta") {
         CrateFlavor::Rmeta
     } else {
         CrateFlavor::Dylib
-    };
-    match get_metadata_section(target, flavor, path, metadata_loader) {
-        Ok(metadata) => metadata.list_crate_metadata(out),
-        Err(msg) => write!(out, "{}\n", msg),
     }
 }
 
@@ -931,7 +949,6 @@ pub(crate) enum CrateError {
     ExternLocationNotExist(Symbol, PathBuf),
     ExternLocationNotFile(Symbol, PathBuf),
     MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
-    MultipleMatchingCrates(Symbol, FxHashMap<Svh, Library>),
     SymbolConflictsCurrent(Symbol),
     SymbolConflictsOthers(Symbol),
     StableCrateIdCollision(Symbol, Symbol),
@@ -972,37 +989,7 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                 sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc });
             }
             CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
-                sess.emit_err(MultipleCandidates { span, flavor: flavor, crate_name, candidates });
-            }
-            CrateError::MultipleMatchingCrates(crate_name, libraries) => {
-                let mut libraries: Vec<_> = libraries.into_values().collect();
-                // Make ordering of candidates deterministic.
-                // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
-                // `sort_by()` could be used instead, but this is in the error path,
-                // so the performance shouldn't matter.
-                libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
-                let candidates = libraries
-                    .iter()
-                    .map(|lib| {
-                        let crate_name = lib.metadata.get_root().name();
-                        let crate_name = crate_name.as_str();
-                        let mut paths = lib.source.paths();
-
-                        // This `unwrap()` should be okay because there has to be at least one
-                        // source file. `CrateSource`'s docs confirm that too.
-                        let mut s = format!(
-                            "\ncrate `{}`: {}",
-                            crate_name,
-                            paths.next().unwrap().display()
-                        );
-                        let padding = 8 + crate_name.len();
-                        for path in paths {
-                            write!(s, "\n{:>padding$}", path.display(), padding = padding).unwrap();
-                        }
-                        s
-                    })
-                    .collect::<String>();
-                sess.emit_err(MultipleMatchingCrates { span, crate_name, candidates });
+                sess.emit_err(MultipleCandidates { span, crate_name, flavor, candidates });
             }
             CrateError::SymbolConflictsCurrent(root_name) => {
                 sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name });
index 1fd35adf1bd2cc4c4ac7f865e10d55d0d1a04b82..59869ee417377635ff55a3093aa64ebb3f2779ca 100644 (file)
@@ -45,7 +45,7 @@ pub fn find_native_static_library(
 
     for path in search_paths {
         for (prefix, suffix) in &formats {
-            let test = path.join(format!("{}{}{}", prefix, name, suffix));
+            let test = path.join(format!("{prefix}{name}{suffix}"));
             if test.exists() {
                 return test;
             }
index 99d8225a4c391381075f18b736bdb816771ffebe..143d8f2f1e18d1fca476640d18af792bcfecf2c1 100644 (file)
@@ -462,7 +462,7 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext {
                 .root
                 .syntax_contexts
                 .get(cdata, id)
-                .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
+                .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}"))
                 .decode((cdata, sess))
         })
     }
@@ -806,7 +806,7 @@ fn get_span(self, index: DefIndex, sess: &Session) -> Span {
             .tables
             .def_span
             .get(self, index)
-            .unwrap_or_else(|| panic!("Missing span for {:?}", index))
+            .unwrap_or_else(|| panic!("Missing span for {index:?}"))
             .decode((self, sess))
     }
 
@@ -1249,7 +1249,7 @@ fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span {
             .tables
             .proc_macro_quoted_spans
             .get(self, index)
-            .unwrap_or_else(|| panic!("Missing proc macro quoted span: {:?}", index))
+            .unwrap_or_else(|| panic!("Missing proc macro quoted span: {index:?}"))
             .decode((self, sess))
     }
 
index 9d0ccfeb16898309ae374f4b6b392e032eb4d550..cb451931dfe179d51047b73036f80a9f16c14865 100644 (file)
@@ -223,14 +223,14 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     generator_kind => { table }
     trait_def => { table }
     deduced_param_attrs => { table }
-    collect_trait_impl_trait_tys => {
+    collect_return_position_impl_trait_in_trait_tys => {
         Ok(cdata
             .root
             .tables
             .trait_impl_trait_tys
             .get(cdata, def_id.index)
             .map(|lazy| lazy.decode((cdata, tcx)))
-            .process_decoded(tcx, || panic!("{:?} does not have trait_impl_trait_tys", def_id)))
+            .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
      }
 
     visibility => { cdata.get_visibility(def_id.index) }
index 40c94b372bbf39d3bb5ece8cdb1c9c70c6c16397..a6133f1b417af89bea3b1526fcb2ad97edd164d0 100644 (file)
@@ -58,7 +58,7 @@ fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
         let _ = d.read_raw_bytes(len);
 
         let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| {
-            panic!("decode error: {}", e);
+            panic!("decode error: {e}");
         });
         DefPathHashMapRef::OwnedFromMetadata(inner)
     }
index 65beb744cf80c30239f2d6b8ec10e7386f32a31e..0d9f216700fb1fc825eb704e388ed849a11652ee 100644 (file)
@@ -145,7 +145,7 @@ fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for CrateNum {
     fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
         if *self != LOCAL_CRATE && s.is_proc_macro {
-            panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self);
+            panic!("Attempted to encode non-local CrateNum {self:?} for proc-macro crate");
         }
         s.emit_u32(self.as_u32());
     }
@@ -276,7 +276,7 @@ fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
                 // Introduce a new scope so that we drop the 'lock()' temporary
                 match &*source_file.external_src.lock() {
                     ExternalSource::Foreign { metadata_index, .. } => *metadata_index,
-                    src => panic!("Unexpected external source {:?}", src),
+                    src => panic!("Unexpected external source {src:?}"),
                 }
             };
 
@@ -733,12 +733,9 @@ macro_rules! stat {
             let prefix = "meta-stats";
             let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
 
-            eprintln!("{} METADATA STATS", prefix);
+            eprintln!("{prefix} METADATA STATS");
             eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size");
-            eprintln!(
-                "{} ----------------------------------------------------------------",
-                prefix
-            );
+            eprintln!("{prefix} ----------------------------------------------------------------");
             for (label, size) in stats {
                 eprintln!(
                     "{} {:<23}{:>10} ({:4.1}%)",
@@ -748,10 +745,7 @@ macro_rules! stat {
                     perc(size)
                 );
             }
-            eprintln!(
-                "{} ----------------------------------------------------------------",
-                prefix
-            );
+            eprintln!("{prefix} ----------------------------------------------------------------");
             eprintln!(
                 "{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
                 prefix,
@@ -759,7 +753,7 @@ macro_rules! stat {
                 to_readable_str(total_bytes),
                 perc(zero_bytes)
             );
-            eprintln!("{}", prefix);
+            eprintln!("{prefix}");
         }
 
         root
@@ -1197,7 +1191,7 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.params_in_repr[def_id] <- params_in_repr);
             }
             if should_encode_trait_impl_trait_tys(tcx, def_id)
-                && let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id)
+                && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
             {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
index 99e692ccb584a8ac30c9f60e0c6b224cfaa814c7..883554f959ccb65240f9361f9af2a278fcf92f1d 100644 (file)
@@ -69,7 +69,7 @@ fn next(&mut self) -> Option<Self::Item> {
         }
         loop {
             // There are nodes that do not have entries, so we need to skip them.
-            let parent_id = self.map.get_parent_node(self.current_id);
+            let parent_id = self.map.parent_id(self.current_id);
 
             if parent_id == self.current_id {
                 self.current_id = CRATE_HIR_ID;
@@ -246,7 +246,7 @@ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
             },
             Node::Variant(_) => DefKind::Variant,
             Node::Ctor(variant_data) => {
-                let ctor_of = match self.find(self.get_parent_node(hir_id)) {
+                let ctor_of = match self.find_parent(hir_id) {
                     Some(Node::Item(..)) => def::CtorOf::Struct,
                     Some(Node::Variant(..)) => def::CtorOf::Variant,
                     _ => unreachable!(),
@@ -257,7 +257,7 @@ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
                 }
             }
             Node::AnonConst(_) => {
-                let inline = match self.find(self.get_parent_node(hir_id)) {
+                let inline = match self.find_parent(hir_id) {
                     Some(Node::Expr(&Expr {
                         kind: ExprKind::ConstBlock(ref anon_const), ..
                     })) if anon_const.hir_id == hir_id => true,
@@ -298,7 +298,7 @@ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
     /// Finds the id of the parent node to this one.
     ///
     /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
-    pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
+    pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
         if id.local_id == ItemLocalId::from_u32(0) {
             Some(self.tcx.hir_owner_parent(id.owner))
         } else {
@@ -312,11 +312,19 @@ pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
     }
 
     #[track_caller]
-    pub fn get_parent_node(self, hir_id: HirId) -> HirId {
-        self.find_parent_node(hir_id)
+    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)))
     }
 
+    pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
+        self.get(self.parent_id(hir_id))
+    }
+
+    pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> {
+        self.find(self.opt_parent_id(hir_id)?)
+    }
+
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
     pub fn find(self, id: HirId) -> Option<Node<'hir>> {
         if id.local_id == ItemLocalId::from_u32(0) {
@@ -414,7 +422,7 @@ pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
     /// which this is the body of, i.e., a `fn`, `const` or `static`
     /// item (possibly associated), a closure, or a `hir::AnonConst`.
     pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
-        let parent = self.get_parent_node(hir_id);
+        let parent = self.parent_id(hir_id);
         assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)), "{hir_id:?}");
         parent
     }
@@ -642,21 +650,21 @@ pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) {
     }
 
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
-    /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+    /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
     #[inline]
     pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir {
         ParentHirIterator { current_id, map: self }
     }
 
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
-    /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+    /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
     #[inline]
     pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> {
         self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.find(id)?)))
     }
 
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
-    /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+    /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
     #[inline]
     pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
         ParentOwnerIterator { current_id, map: self }
@@ -664,7 +672,7 @@ pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
 
     /// Checks if the node is left-hand side of an assignment.
     pub fn is_lhs(self, id: HirId) -> bool {
-        match self.find(self.get_parent_node(id)) {
+        match self.find_parent(id) {
             Some(Node::Expr(expr)) => match expr.kind {
                 ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
                 _ => false,
@@ -892,7 +900,7 @@ fn opt_ident(self, id: HirId) -> Option<Ident> {
             Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
             // A `Ctor` doesn't have an identifier itself, but its parent
             // struct/variant does. Compare with `hir::Map::opt_span`.
-            Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
+            Node::Ctor(..) => match self.find_parent(id)? {
                 Node::Item(item) => Some(item.ident),
                 Node::Variant(variant) => Some(variant.ident),
                 _ => unreachable!(),
@@ -1021,7 +1029,7 @@ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) ->
                 ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
                 _ => named_span(item.span, item.ident, None),
             },
-            Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
+            Node::Ctor(_) => return self.opt_span(self.parent_id(hir_id)),
             Node::Expr(Expr {
                 kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
                 span,
@@ -1063,7 +1071,7 @@ pub fn span_with_body(self, hir_id: HirId) -> Span {
             Node::PatField(field) => field.span,
             Node::Arm(arm) => arm.span,
             Node::Block(block) => block.span,
-            Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)),
+            Node::Ctor(..) => self.span_with_body(self.parent_id(hir_id)),
             Node::Lifetime(lifetime) => lifetime.ident.span,
             Node::GenericParam(param) => param.span,
             Node::Infer(i) => i.span,
@@ -1093,7 +1101,7 @@ pub fn node_to_string(self, id: HirId) -> String {
     /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
     /// called with the HirId for the `{ ... }` anon const
     pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
-        match self.get(self.get_parent_node(anon_const)) {
+        match self.get_parent(anon_const) {
             Node::GenericParam(GenericParam {
                 def_id: param_id,
                 kind: GenericParamKind::Const { .. },
@@ -1160,7 +1168,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
         hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
         upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
         source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
-        if tcx.sess.opts.unstable_opts.incremental_relative_spans {
+        if tcx.sess.opts.incremental_relative_spans() {
             let definitions = tcx.definitions_untracked();
             let mut owner_spans: Vec<_> = krate
                 .owners
index 3f6e29ad611c911daf807d72be51dc5eb6e00780..a633201e3d9ae82091808f6684ebee834eb5434a 100644 (file)
@@ -160,9 +160,13 @@ pub fn provide(providers: &mut Providers) {
         } else if let Node::TraitItem(&TraitItem {
             kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
             ..
+        })
+        | Node::ForeignItem(&ForeignItem {
+            kind: ForeignItemKind::Fn(_, idents, _),
+            ..
         }) = hir.get(hir_id)
         {
-            tcx.arena.alloc_slice(idents)
+            idents
         } else {
             span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
         }
index 0b32f67a81e16bb3fcea96e999fdb1bf273b1f00..614cf1a0051da8b423c96e536cb018646518ab97 100644 (file)
@@ -213,9 +213,7 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
-pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
-
-pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
+pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
 
 /// Indicates whether or not we were able to prove the query to be
 /// true.
index 51df42f6d14e06a3ddfff7346d82fa3f14a85e06..eb48b325e84ebd22be75e0fc1951dd7514b32af0 100644 (file)
@@ -182,7 +182,7 @@ pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId
             if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
                 return id;
             }
-            let next = hir.get_parent_node(id);
+            let next = hir.parent_id(id);
             if next == id {
                 bug!("lint traversal reached the root of the crate");
             }
index 01fe72de61258bfac36a8f780f12ac1f1d3255ba..5ca4d260179ceff29f982033a0a3cb4e171e089d 100644 (file)
@@ -1,3 +1,13 @@
+/// A macro for triggering an ICE.
+/// Calling `bug` instead of panicking will result in a nicer error message and should
+/// therefore be prefered over `panic`/`unreachable` or others.
+///
+/// If you have a span available, you should use [`span_bug`] instead.
+///
+/// If the bug should only be emitted when compilation didn't fail, [`Session::delay_span_bug`] may be useful.
+///
+/// [`Session::delay_span_bug`]: rustc_session::Session::delay_span_bug
+/// [`span_bug`]: crate::span_bug
 #[macro_export]
 macro_rules! bug {
     () => ( $crate::bug!("impossible case reached") );
@@ -8,6 +18,14 @@ macro_rules! bug {
     });
 }
 
+/// A macro for triggering an ICE with a span.
+/// Calling `span_bug!` instead of panicking will result in a nicer error message and point
+/// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
+/// ICEs.
+///
+/// If the bug should only be emitted when compilation didn't fail, [`Session::delay_span_bug`] may be useful.
+///
+/// [`Session::delay_span_bug`]: rustc_session::Session::delay_span_bug
 #[macro_export]
 macro_rules! span_bug {
     ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) });
index a89e6566d56affcb6dfeddb285a18e373bf3c663..14bdff4568f5e65f8e1fd4c6355bdaf89a4ae4d2 100644 (file)
@@ -2506,7 +2506,7 @@ fn from_opt_const_arg_anon_const(
         }
 
         let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-        let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
+        let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) {
             if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
                 InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
             } else {
index 013a1bccd3bd1fd85af72a5a31db156e4e0c3416..438f36373ca91b0682484f1052eefd7ad1aa889a 100644 (file)
@@ -1,4 +1,4 @@
-use smallvec::{smallvec, SmallVec};
+use smallvec::SmallVec;
 
 use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind};
 use rustc_ast::InlineAsmTemplatePiece;
index 2ee3f551529f986c44525f9857994b4a29cbafba..1a264d2d5af9a0d6ab1d8eebc2aaba14b9bde5ed 100644 (file)
@@ -3,15 +3,15 @@
 //! ## Overview
 //!
 //! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by the following macro. The code is written according
-//! to the following conventions:
+//! but both are generated by the `make_mir_visitor` macro.
+//! The code is written according to the following conventions:
 //!
 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type
 //! - `visit_foo`, by default, calls `super_foo`
 //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
 //!
-//! This allows you as a user to override `visit_foo` for types are
-//! interested in, and invoke (within that method) call
+//! This allows you to override `visit_foo` for types you are
+//! interested in, and invoke (within that method call)
 //! `self.super_foo` to get the default behavior. Just as in an OO
 //! language, you should never call `super` methods ordinarily except
 //! in that circumstance.
index ab512804330b9f647ca9bc14edf2e0d698b53b4a..37db2274f678fa0ab42f94847d6f43fed9155f91 100644 (file)
         separate_provide_extern
     }
 
-    query collect_trait_impl_trait_tys(key: DefId)
+    query collect_return_position_impl_trait_in_trait_tys(key: DefId)
         -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
     {
         desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
         desc { "checking to see if `{}` permits being left zeroed", key.ty }
     }
 
-    query compare_assoc_const_impl_item_with_trait_item(
+    query compare_impl_const(
         key: (LocalDefId, DefId)
     ) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) }
index 6a149be3137ee69ecc0145939aa4e6701aded6ec..543f5b87e00bccd3a0c887f9c06f31ce3149f923 100644 (file)
 
 pub mod type_op {
     use crate::ty::fold::TypeFoldable;
-    use crate::ty::subst::UserSubsts;
-    use crate::ty::{Predicate, Ty};
-    use rustc_hir::def_id::DefId;
+    use crate::ty::{Predicate, Ty, UserType};
     use std::fmt;
 
     #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
     #[derive(TypeFoldable, TypeVisitable)]
     pub struct AscribeUserType<'tcx> {
         pub mir_ty: Ty<'tcx>,
-        pub def_id: DefId,
-        pub user_substs: UserSubsts<'tcx>,
+        pub user_ty: UserType<'tcx>,
     }
 
     impl<'tcx> AscribeUserType<'tcx> {
-        pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
-            Self { mir_ty, def_id, user_substs }
+        pub fn new(mir_ty: Ty<'tcx>, user_ty: UserType<'tcx>) -> Self {
+            Self { mir_ty, user_ty }
         }
     }
 
index ffdac93bcd09abefb3d4754ea79a594784f4f9c2..9e4f90caab0b5957b2469fc6520d7771bd3b096d 100644 (file)
@@ -21,7 +21,7 @@ pub fn erase_regions<T>(self, value: T) -> T
         T: TypeFoldable<'tcx>,
     {
         // If there's nothing to erase avoid performing the query at all
-        if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
+        if !value.has_type_flags(TypeFlags::HAS_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
             return value;
         }
         debug!("erase_regions({:?})", value);
index 14d07608a780e6c5b33b6dbae204401251b39088..50554cf9a82c85e7e53112ae0da4e6a3bb723f6e 100644 (file)
@@ -457,7 +457,7 @@ pub fn note_and_explain_type_err(
                             .def_id
                             .as_local()
                             .map(|id| hir.local_def_id_to_hir_id(id))
-                            .and_then(|id| self.hir().find(self.hir().get_parent_node(id)))
+                            .and_then(|id| self.hir().find_parent(id))
                             .as_ref()
                             .and_then(|node| node.generics())
                         {
index 8306d670a65deed8e81a4ecd092790b5834786e9..b7eafc4b437385ac986f29b2c0ef8d09f4972246 100644 (file)
@@ -59,8 +59,18 @@ fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
     {
         let mut computation = FlagComputation::new();
 
-        if !value.bound_vars().is_empty() {
-            computation.flags = computation.flags | TypeFlags::HAS_RE_LATE_BOUND;
+        for bv in value.bound_vars() {
+            match bv {
+                ty::BoundVariableKind::Ty(_) => {
+                    computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
+                }
+                ty::BoundVariableKind::Region(_) => {
+                    computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
+                }
+                ty::BoundVariableKind::Const => {
+                    computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
+                }
+            }
         }
 
         f(&mut computation, value.skip_binder());
@@ -131,6 +141,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
 
             &ty::Bound(debruijn, _) => {
                 self.add_bound_var(debruijn);
+                self.add_flags(TypeFlags::HAS_TY_LATE_BOUND);
             }
 
             &ty::Placeholder(..) => {
@@ -303,6 +314,7 @@ fn add_const(&mut self, c: ty::Const<'_>) {
             }
             ty::ConstKind::Bound(debruijn, _) => {
                 self.add_bound_var(debruijn);
+                self.add_flags(TypeFlags::HAS_CT_LATE_BOUND);
             }
             ty::ConstKind::Param(_) => {
                 self.add_flags(TypeFlags::HAS_CT_PARAM);
index 9e0ca44d0981df0dbcf4afc9a3282310d37d1c1e..00f53afd6632854f824eb5df0d8256d61407ba18 100644 (file)
@@ -670,29 +670,50 @@ fn field_ty_or_layout<'tcx>(
                         });
                     }
 
-                    match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
-                        ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
-                        ty::Dynamic(_, _, ty::Dyn) => {
-                            TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
-                                tcx.lifetimes.re_static,
-                                tcx.mk_array(tcx.types.usize, 3),
-                            ))
-                            /* FIXME: use actual fn pointers
-                            Warning: naively computing the number of entries in the
-                            vtable by counting the methods on the trait + methods on
-                            all parent traits does not work, because some methods can
-                            be not object safe and thus excluded from the vtable.
-                            Increase this counter if you tried to implement this but
-                            failed to do it without duplicating a lot of code from
-                            other places in the compiler: 2
-                            tcx.mk_tup(&[
-                                tcx.mk_array(tcx.types.usize, 3),
-                                tcx.mk_array(Option<fn()>),
-                            ])
-                            */
+                    let mk_dyn_vtable = || {
+                        tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
+                        /* FIXME: use actual fn pointers
+                        Warning: naively computing the number of entries in the
+                        vtable by counting the methods on the trait + methods on
+                        all parent traits does not work, because some methods can
+                        be not object safe and thus excluded from the vtable.
+                        Increase this counter if you tried to implement this but
+                        failed to do it without duplicating a lot of code from
+                        other places in the compiler: 2
+                        tcx.mk_tup(&[
+                            tcx.mk_array(tcx.types.usize, 3),
+                            tcx.mk_array(Option<fn()>),
+                        ])
+                        */
+                    };
+
+                    let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
+                        let metadata = tcx.normalize_erasing_regions(
+                            cx.param_env(),
+                            tcx.mk_projection(metadata_def_id, [pointee]),
+                        );
+
+                        // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
+                        // offers better information than `std::ptr::metadata::VTable`,
+                        // and we rely on this layout information to trigger a panic in
+                        // `std::mem::uninitialized::<&dyn Trait>()`, for example.
+                        if let ty::Adt(def, substs) = metadata.kind()
+                            && Some(def.did()) == tcx.lang_items().dyn_metadata()
+                            && substs.type_at(0).is_trait()
+                        {
+                            mk_dyn_vtable()
+                        } else {
+                            metadata
                         }
-                        _ => bug!("TyAndLayout::field({:?}): not applicable", this),
-                    }
+                    } else {
+                        match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+                            ty::Slice(_) | ty::Str => tcx.types.usize,
+                            ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(),
+                            _ => bug!("TyAndLayout::field({:?}): not applicable", this),
+                        }
+                    };
+
+                    TyMaybeWithLayout::Ty(metadata)
                 }
 
                 // Arrays and slices.
index 136a4906c58de7f1c607e70a90af645b43381c4b..028a03c0b2bdd78d525892e8c5923289af1149e6 100644 (file)
@@ -626,7 +626,7 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
     pub inferred_ty: Ty<'tcx>,
 }
 
-/// Canonicalized user type annotation.
+/// Canonical user type annotation.
 pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
 
 impl<'tcx> CanonicalUserType<'tcx> {
@@ -679,7 +679,7 @@ pub fn is_identity(&self) -> bool {
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum UserType<'tcx> {
     Ty(Ty<'tcx>),
 
index 6d3b94c1fdbf8651c113ba2f7dd73e4fb09cb8bd..cc53659f827986d7ff4b7a72163730bcb8a5f5eb 100644 (file)
@@ -641,11 +641,11 @@ pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
         ty::EarlyBinder(self.type_of(def_id))
     }
 
-    pub fn bound_trait_impl_trait_tys(
+    pub fn bound_return_position_impl_trait_in_trait_tys(
         self,
         def_id: DefId,
     ) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> {
-        ty::EarlyBinder(self.collect_trait_impl_trait_tys(def_id))
+        ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id))
     }
 
     pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
index d5553f84f7517d8531eb348324bef6c259f44b2c..ca445558131380e364370ea518fb37a69a4c7bfa 100644 (file)
@@ -165,6 +165,14 @@ fn is_global(&self) -> bool {
     fn has_late_bound_regions(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
     }
+    /// True if there are any late-bound non-region variables
+    fn has_non_region_late_bound(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
+    }
+    /// True if there are any late-bound variables
+    fn has_late_bound_vars(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
+    }
 
     /// Indicates whether this value still has parameters/placeholders/inference variables
     /// which could be replaced later, in a way that would change the results of `impl`
index 34dbb6e9f68ea1cf6fe295448322edf3f532cea9..708a5e4d059e8acdab8166081f1c6c4d54fee151 100644 (file)
@@ -4,7 +4,7 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, Ty};
 use rustc_data_structures::sso::SsoHashSet;
-use smallvec::{self, SmallVec};
+use smallvec::SmallVec;
 
 // The TypeWalker's stack is hot enough that it's worth going to some effort to
 // avoid heap allocations.
index fd7045d6a03f210da9ebfd54ab975d3ff700e179..b73ae593905353a8d99c97dff746f4db9c375870 100644 (file)
@@ -35,8 +35,7 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
             (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
             (None, _) => panic_any(msg),
         }
-    });
-    unreachable!();
+    })
 }
 
 /// A query to trigger a `delay_span_bug`. Clearly, if one has a `tcx` one can already trigger a
index 3c311729a52aa6dd0f29c912c7230d721ec97bef..03a7f2d70faebb1127bcf952ce28cab88b633923 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_hir as hir;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::thir::*;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
@@ -524,17 +525,19 @@ pub fn emit_unsafe_op_in_unsafe_fn_lint(
         hir_id: hir::HirId,
         span: Span,
     ) {
+        // FIXME: ideally we would want to trim the def paths, but this is not
+        // feasible with the current lint emission API (see issue #106126).
         match self {
-            CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+            CallToUnsafeFunction(Some(did)) => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
                 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
                     span,
-                    function: &tcx.def_path_str(did.unwrap()),
+                    function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
                 },
             ),
-            CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+            CallToUnsafeFunction(None) => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
@@ -594,7 +597,7 @@ pub fn emit_unsafe_op_in_unsafe_fn_lint(
                 span,
                 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
                     span,
-                    function: &tcx.def_path_str(*did),
+                    function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
                 },
             ),
         }
@@ -607,24 +610,24 @@ pub fn emit_requires_unsafe_err(
         unsafe_op_in_unsafe_fn_allowed: bool,
     ) {
         match self {
-            CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+            CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
                 tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
-                    function: &tcx.def_path_str(did.unwrap()),
+                    function: &tcx.def_path_str(*did),
                 });
             }
-            CallToUnsafeFunction(did) if did.is_some() => {
+            CallToUnsafeFunction(Some(did)) => {
                 tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
                     span,
-                    function: &tcx.def_path_str(did.unwrap()),
+                    function: &tcx.def_path_str(*did),
                 });
             }
-            CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+            CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
                 tcx.sess.emit_err(
                     CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
                 );
             }
-            CallToUnsafeFunction(..) => {
+            CallToUnsafeFunction(None) => {
                 tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
             }
             UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
index a94d8d6c6431c81c0d95e2f525d9cff0d8c12d08..e7ee0d9e908e0556746b5f01fc413d1a5f731256 100644 (file)
@@ -247,14 +247,14 @@ fn check_let_reachability(
 
     fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId) -> bool {
         let hir = self.tcx.hir();
-        let parent = hir.get_parent_node(pat_id);
+        let parent = hir.parent_id(pat_id);
 
         // First, figure out if the given pattern is part of a let chain,
         // and if so, obtain the top node of the chain.
         let mut top = parent;
         let mut part_of_chain = false;
         loop {
-            let new_top = hir.get_parent_node(top);
+            let new_top = hir.parent_id(top);
             if let hir::Node::Expr(
                 hir::Expr {
                     kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs),
@@ -1054,7 +1054,7 @@ pub enum LetSource {
 fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
     let hir = tcx.hir();
 
-    let parent = hir.get_parent_node(pat_id);
+    let parent = hir.parent_id(pat_id);
     let_source_parent(tcx, parent, Some(pat_id))
 }
 
@@ -1073,7 +1073,7 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
         _ => {}
     }
 
-    let parent_parent = hir.get_parent_node(parent);
+    let parent_parent = hir.parent_id(parent);
     let parent_parent_node = hir.get(parent_parent);
     match parent_parent_node {
         hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => {
@@ -1085,8 +1085,8 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
         _ => {}
     }
 
-    let parent_parent_parent = hir.get_parent_node(parent_parent);
-    let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);
+    let parent_parent_parent = hir.parent_id(parent_parent);
+    let parent_parent_parent_parent = hir.parent_id(parent_parent_parent);
     let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent);
 
     if let hir::Node::Expr(hir::Expr {
index 5ff6b9e7e69b4f8257a49d4190a996da6b75e017..077a21fc8afc03fa1faa2886643ffc2c90665be8 100644 (file)
@@ -287,7 +287,7 @@ fn join_state_into_successors_of<'tcx, A>(
                 | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
                     if unwind == bb =>
                 {
-                    if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
+                    if dead_unwinds.map_or(true, |dead| !dead.contains(pred)) {
                         propagate(pred, exit_state);
                     }
                 }
index 209e6f7ac9fe41c98c605de5e70388e67f2d3306..490be166a91d9269926ed46249b010c04087ddaf 100644 (file)
@@ -143,7 +143,7 @@ fn fmt_diff<T, C>(
             ", "
         };
 
-        write!(f, "{}", delim)?;
+        write!(f, "{delim}")?;
         idx.fmt_with(ctxt, f)?;
         first = false;
     }
@@ -164,7 +164,7 @@ fn fmt_diff<T, C>(
             ", "
         };
 
-        write!(f, "{}", delim)?;
+        write!(f, "{delim}")?;
         idx.fmt_with(ctxt, f)?;
         first = false;
     }
index c9d5601f2074c958ca160a56bd7925ae48bb94a0..96c42894b697e77358f997e24e847342aaa76354 100644 (file)
@@ -71,7 +71,7 @@ impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
 
     fn graph_id(&self) -> dot::Id<'_> {
         let name = graphviz_safe_def_name(self.body.source.def_id());
-        dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
+        dot::Id::new(format!("graph_for_def_id_{name}")).unwrap()
     }
 
     fn node_id(&self, n: &Self::Node) -> dot::Id<'_> {
@@ -190,7 +190,7 @@ fn write_node_label(
             " cellpadding=\"3\"",
             " sides=\"rb\"",
         );
-        write!(w, r#"<table{fmt}>"#, fmt = table_fmt)?;
+        write!(w, r#"<table{table_fmt}>"#)?;
 
         // A + B: Block header
         match self.style {
@@ -372,7 +372,7 @@ fn write_block_header_with_state_columns(
         write!(w, concat!("<tr>", r#"<td colspan="2" {fmt}>MIR</td>"#,), fmt = fmt,)?;
 
         for name in state_column_names {
-            write!(w, "<td {fmt}>{name}</td>", fmt = fmt, name = name)?;
+            write!(w, "<td {fmt}>{name}</td>")?;
         }
 
         write!(w, "</tr>")
@@ -394,18 +394,18 @@ fn write_statements_and_terminator(
         };
 
         for (i, statement) in body[block].statements.iter().enumerate() {
-            let statement_str = format!("{:?}", statement);
-            let index_str = format!("{}", i);
+            let statement_str = format!("{statement:?}");
+            let index_str = format!("{i}");
 
             let after = next_in_dataflow_order(&mut afters);
             let before = befores.as_mut().map(next_in_dataflow_order);
 
             self.write_row(w, &index_str, &statement_str, |_this, w, fmt| {
                 if let Some(before) = before {
-                    write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = before)?;
+                    write!(w, r#"<td {fmt} align="left">{before}</td>"#)?;
                 }
 
-                write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = after)
+                write!(w, r#"<td {fmt} align="left">{after}</td>"#)
             })?;
         }
 
@@ -421,10 +421,10 @@ fn write_statements_and_terminator(
 
         self.write_row(w, "T", &terminator_str, |_this, w, fmt| {
             if let Some(before) = before {
-                write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = before)?;
+                write!(w, r#"<td {fmt} align="left">{before}</td>"#)?;
             }
 
-            write!(w, r#"<td {fmt} align="left">{diff}</td>"#, fmt = fmt, diff = after)
+            write!(w, r#"<td {fmt} align="left">{after}</td>"#)
         })
     }
 
index 9b053985bedf6823f13a47fe5f5a6d5770cc38b8..5f22a418de863bbca88665d1389490cbee8b6764 100644 (file)
@@ -129,13 +129,13 @@ impl<'tcx> fmt::Debug for MovePath<'tcx> {
     fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(w, "MovePath {{")?;
         if let Some(parent) = self.parent {
-            write!(w, " parent: {:?},", parent)?;
+            write!(w, " parent: {parent:?},")?;
         }
         if let Some(first_child) = self.first_child {
-            write!(w, " first_child: {:?},", first_child)?;
+            write!(w, " first_child: {first_child:?},")?;
         }
         if let Some(next_sibling) = self.next_sibling {
-            write!(w, " next_sibling: {:?}", next_sibling)?;
+            write!(w, " next_sibling: {next_sibling:?}")?;
         }
         write!(w, " place: {:?} }}", self.place)
     }
index fe5ee4011ab8483bb3987779220c77ce7af56577..0522c657939f5e100c7827dd319862ce3eedaf09 100644 (file)
@@ -920,7 +920,7 @@ fn debug_with_context<V: Debug + Eq>(
 ) -> std::fmt::Result {
     for (local, place) in map.locals.iter_enumerated() {
         if let Some(place) = place {
-            debug_with_context_rec(*place, &format!("{:?}", local), new, old, map, f)?;
+            debug_with_context_rec(*place, &format!("{local:?}"), new, old, map, f)?;
         }
     }
     Ok(())
index e384cfe165990c47940bde2566b8da034d49fe33..5c45abc5a170ec63bae49cbb386edd0d854accfe 100644 (file)
@@ -655,11 +655,7 @@ fn const_prop(&mut self, rvalue: &Rvalue<'tcx>, place: Place<'tcx>) -> Option<()
             return None;
         }
 
-        if self.tcx.sess.mir_opt_level() >= 4 {
-            self.eval_rvalue_with_identities(rvalue, place)
-        } else {
-            self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
-        }
+        self.eval_rvalue_with_identities(rvalue, place)
     }
 
     // Attempt to use algebraic identities to eliminate constant expressions
index 42c580c63f06046e56d9b81290c7bf8fb0ee4c75..09546330cec92672a2a5c906ba1d1847c108e7ed 100644 (file)
@@ -71,7 +71,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
         bbs[block].statements[statement_index].make_nop();
     }
 
-    crate::simplify::SimplifyLocals.run_pass(tcx, body)
+    crate::simplify::simplify_locals(body, tcx)
 }
 
 pub struct DeadStoreElimination;
index 9d560f5c837e2d75e75f6899d65199bdef8fe710..4219e6280ebbca481424a6b7ee3bbef6ed25d41c 100644 (file)
@@ -1,6 +1,7 @@
 //! Inlining pass for MIR functions
 use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -27,6 +28,8 @@
 
 const UNKNOWN_SIZE_COST: usize = 10;
 
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
 pub struct Inline;
 
 #[derive(Copy, Clone, Debug)]
@@ -86,8 +89,13 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-    let mut this =
-        Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+    let mut this = Inliner {
+        tcx,
+        param_env,
+        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+        history: Vec::new(),
+        changed: false,
+    };
     let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
     this.process_blocks(body, blocks);
     this.changed
@@ -98,12 +106,26 @@ struct Inliner<'tcx> {
     param_env: ParamEnv<'tcx>,
     /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
+    /// Stack of inlined instances.
+    /// We only check the `DefId` and not the substs because we want to
+    /// avoid inlining cases of polymorphic recursion.
+    /// The number of `DefId`s is finite, so checking history is enough
+    /// to ensure that we do not loop endlessly while inlining.
+    history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
 }
 
 impl<'tcx> Inliner<'tcx> {
     fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+        // How many callsites in this body are we allowed to inline? We need to limit this in order
+        // to prevent super-linear growth in MIR size
+        let inline_limit = match self.history.len() {
+            0 => usize::MAX,
+            1..=TOP_DOWN_DEPTH_LIMIT => 1,
+            _ => return,
+        };
+        let mut inlined_count = 0;
         for bb in blocks {
             let bb_data = &caller_body[bb];
             if bb_data.is_cleanup {
@@ -122,12 +144,16 @@ fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBl
                     debug!("not-inlined {} [{}]", callsite.callee, reason);
                     continue;
                 }
-                Ok(_) => {
+                Ok(new_blocks) => {
                     debug!("inlined {}", callsite.callee);
                     self.changed = true;
-                    // We could process the blocks returned by `try_inlining` here. However, that
-                    // leads to exponential compile times due to the top-down nature of this kind
-                    // of inlining.
+                    inlined_count += 1;
+                    if inlined_count == inline_limit {
+                        return;
+                    }
+                    self.history.push(callsite.callee.def_id());
+                    self.process_blocks(caller_body, new_blocks);
+                    self.history.pop();
                 }
             }
         }
@@ -289,7 +315,7 @@ fn resolve_callsite(
     ) -> Option<CallSite<'tcx>> {
         // Only consider direct calls to functions
         let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { ref func, target, .. } = terminator.kind {
+        if let TerminatorKind::Call { ref func, target, fn_span, .. } = terminator.kind {
             let func_ty = func.ty(caller_body, self.tcx);
             if let ty::FnDef(def_id, substs) = *func_ty.kind() {
                 // To resolve an instance its substs have to be fully normalized.
@@ -301,15 +327,14 @@ fn resolve_callsite(
                     return None;
                 }
 
+                if self.history.contains(&callee.def_id()) {
+                    return None;
+                }
+
                 let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
+                let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
 
-                return Some(CallSite {
-                    callee,
-                    fn_sig,
-                    block: bb,
-                    target,
-                    source_info: terminator.source_info,
-                });
+                return Some(CallSite { callee, fn_sig, block: bb, target, source_info });
             }
         }
 
index ae79c2290f6d30c0f923a2f75e6aaac9f6b95f17..16b8a901f36512140a87c147910aeabcec5eadfe 100644 (file)
@@ -524,11 +524,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
 /// Returns the sequence of passes that do the initial cleanup of runtime MIR.
 fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let passes: &[&dyn MirPass<'tcx>] = &[
-        &elaborate_box_derefs::ElaborateBoxDerefs,
-        &lower_intrinsics::LowerIntrinsics,
-        &simplify::SimplifyCfg::new("elaborate-drops"),
-    ];
+    let passes: &[&dyn MirPass<'tcx>] =
+        &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
 
     pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
 }
@@ -560,6 +557,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &multiple_return_terminators::MultipleReturnTerminators,
             &instcombine::InstCombine,
             &separate_const_switch::SeparateConstSwitch,
+            &simplify::SimplifyLocals::new("before-const-prop"),
             //
             // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
             &const_prop::ConstProp,
@@ -578,7 +576,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
             &o1(simplify::SimplifyCfg::new("final")),
             &nrvo::RenameReturnPlace,
-            &simplify::SimplifyLocals,
+            &simplify::SimplifyLocals::new("final"),
             &multiple_return_terminators::MultipleReturnTerminators,
             &deduplicate_blocks::DeduplicateBlocks,
             // Some cleanup necessary at least for LLVM and potentially other codegen backends.
index 8212a7b523bbc98d5d1e4d8d76e57864432d61df..8f6abe7a912feefefadb5ac24abbc8dbe97c3af9 100644 (file)
@@ -379,9 +379,21 @@ fn save_unreachable_coverage(
     ));
 }
 
-pub struct SimplifyLocals;
+pub struct SimplifyLocals {
+    label: String,
+}
+
+impl SimplifyLocals {
+    pub fn new(label: &str) -> SimplifyLocals {
+        SimplifyLocals { label: format!("SimplifyLocals-{}", label) }
+    }
+}
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+    fn name(&self) -> &str {
+        &self.label
+    }
+
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
@@ -557,6 +569,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
 
                     StatementKind::SetDiscriminant { ref place, .. }
                     | StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
+                    StatementKind::Nop => false,
                     _ => true,
                 };
 
index 6ee5330b63f51a4ea7e79ca5a2f62fe5ff7f2ef6..c8af10576b42fcf4526aafc92e2985774d9d2680 100644 (file)
@@ -6,6 +6,8 @@ edition = "2021"
 [lib]
 
 [dependencies]
+serde = "1"
+serde_json = "1"
 smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
 tracing = "0.1"
 rustc_data_structures = { path = "../rustc_data_structures" }
index 59cc500a99da7267f91fa56cadd0fb131246f2eb..b573df4325051306236920cdbdc7f273e3a13395 100644 (file)
@@ -526,7 +526,7 @@ fn collect_items_rec<'tcx>(
         let formatted_item = with_no_trimmed_paths!(starting_point.node.to_string());
         tcx.sess.span_note_without_error(
             starting_point.span,
-            &format!("the above error was encountered while instantiating `{}`", formatted_item),
+            &format!("the above error was encountered while instantiating `{formatted_item}`"),
         );
     }
     inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items);
index f15cf54718e2b7221bbb70fb9261f36af32fd525..aa3227cac2de4ac6dd09c269019a3ab5a915d208 100644 (file)
@@ -50,7 +50,7 @@ fn into_diagnostic(
             // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
             // or a label with a dynamic value in a hard-coded string, but I haven't figured out
             // how to combine the two. 😢
-            diag.span_label(span, format!("generic parameter `{}` is unused", name));
+            diag.span_label(span, format!("generic parameter `{name}` is unused"));
         }
         diag
     }
index 4f25fc71314ea1ae738d29bc4ceff7bc61695c2a..fd6bcad18983a334d5b3e59eb6af2e98f4d3bacb 100644 (file)
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync;
-use rustc_hir::def_id::DefIdSet;
+use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE};
 use rustc_middle::mir;
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{CodegenUnit, Linkage};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::SwitchWithOptPath;
+use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
 use rustc_span::symbol::Symbol;
 
 use crate::collector::InliningMap;
@@ -285,7 +285,7 @@ fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
         use std::fmt::Write;
 
         let s = &mut String::new();
-        let _ = writeln!(s, "{}", label);
+        let _ = writeln!(s, "{label}");
         for cgu in cgus {
             let _ =
                 writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate());
@@ -355,9 +355,8 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
             } else {
                 if mode_string != "lazy" {
                     let message = format!(
-                        "Unknown codegen-item collection mode '{}'. \
-                                           Falling back to 'lazy' mode.",
-                        mode_string
+                        "Unknown codegen-item collection mode '{mode_string}'. \
+                                           Falling back to 'lazy' mode."
                     );
                     tcx.sess.warn(&message);
                 }
@@ -417,7 +416,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
     // Output monomorphization stats per def_id
     if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
         if let Err(err) =
-            dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+            dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE))
         {
             tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
         }
@@ -470,7 +469,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
         item_keys.sort();
 
         for item in item_keys {
-            println!("MONO_ITEM {}", item);
+            println!("MONO_ITEM {item}");
         }
     }
 
@@ -483,7 +482,7 @@ fn dump_mono_items_stats<'tcx>(
     tcx: TyCtxt<'tcx>,
     codegen_units: &[CodegenUnit<'tcx>],
     output_directory: &Option<PathBuf>,
-    crate_name: Option<&str>,
+    crate_name: Symbol,
 ) -> Result<(), Box<dyn std::error::Error>> {
     let output_directory = if let Some(ref directory) = output_directory {
         fs::create_dir_all(directory)?;
@@ -492,9 +491,11 @@ fn dump_mono_items_stats<'tcx>(
         Path::new(".")
     };
 
-    let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+    let format = tcx.sess.opts.unstable_opts.dump_mono_stats_format;
+    let ext = format.extension();
+    let filename = format!("{crate_name}.mono_items.{ext}");
     let output_path = output_directory.join(&filename);
-    let file = File::create(output_path)?;
+    let file = File::create(&output_path)?;
     let mut file = BufWriter::new(file);
 
     // Gather instantiated mono items grouped by def_id
@@ -508,30 +509,44 @@ fn dump_mono_items_stats<'tcx>(
         }
     }
 
+    #[derive(serde::Serialize)]
+    struct MonoItem {
+        name: String,
+        instantiation_count: usize,
+        size_estimate: usize,
+        total_estimate: usize,
+    }
+
     // Output stats sorted by total instantiated size, from heaviest to lightest
     let mut stats: Vec<_> = items_per_def_id
         .into_iter()
         .map(|(def_id, items)| {
+            let name = with_no_trimmed_paths!(tcx.def_path_str(def_id));
             let instantiation_count = items.len();
             let size_estimate = items[0].size_estimate(tcx);
             let total_estimate = instantiation_count * size_estimate;
-            (def_id, instantiation_count, size_estimate, total_estimate)
+            MonoItem { name, instantiation_count, size_estimate, total_estimate }
         })
         .collect();
-    stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+    stats.sort_unstable_by_key(|item| cmp::Reverse(item.total_estimate));
 
     if !stats.is_empty() {
-        writeln!(
-            file,
-            "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
-        )?;
-        writeln!(file, "| --- | ---: | ---: | ---: |")?;
-        for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
-            let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
-            writeln!(
-                file,
-                "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
-            )?;
+        match format {
+            DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?,
+            DumpMonoStatsFormat::Markdown => {
+                writeln!(
+                    file,
+                    "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+                )?;
+                writeln!(file, "| --- | ---: | ---: | ---: |")?;
+
+                for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats {
+                    writeln!(
+                        file,
+                        "| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |"
+                    )?;
+                }
+            }
         }
     }
 
@@ -580,6 +595,6 @@ pub fn provide(providers: &mut Providers) {
         let (_, all) = tcx.collect_and_partition_mono_items(());
         all.iter()
             .find(|cgu| cgu.name() == name)
-            .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name))
+            .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
     };
 }
index 6a4d2df1ead158b8612f7b4ad0c14cf8f26e5c4b..33e1f6ce3428e96559564a6c369c34ca3cc2d2c5 100644 (file)
@@ -40,12 +40,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
         let new_size = tcx
             .layout_of(param_env.and(after_feature_tys))
             .map(|l| format!("{:?}", l.size.bytes()))
-            .unwrap_or_else(|e| format!("Failed {:?}", e));
+            .unwrap_or_else(|e| format!("Failed {e:?}"));
 
         let old_size = tcx
             .layout_of(param_env.and(before_feature_tys))
             .map(|l| format!("{:?}", l.size.bytes()))
-            .unwrap_or_else(|e| format!("Failed {:?}", e));
+            .unwrap_or_else(|e| format!("Failed {e:?}"));
 
         let closure_span = tcx.def_span(closure_def_id);
         let src_file = tcx.sess.source_map().span_to_filename(closure_span);
@@ -54,7 +54,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
             .source_map()
             .span_to_lines(closure_span)
             .map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last()))
-            .unwrap_or_else(|e| format!("{:?}", e));
+            .unwrap_or_else(|e| format!("{e:?}"));
 
         if let Err(e) = writeln!(
             file,
@@ -64,7 +64,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
             src_file.prefer_local(),
             line_nos
         ) {
-            eprintln!("Error writing to file {}", e)
+            eprintln!("Error writing to file {e}")
         }
     }
 }
index 18a0bee9c2e5ee83ba98e4543fdc54b2befb3d8d..574591529f33194f240067c2a420ba18923b7223 100644 (file)
@@ -1229,3 +1229,11 @@ pub(crate) struct FnTypoWithImpl {
     #[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")]
     pub fn_span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_fn_path_found_fn_keyword)]
+pub(crate) struct ExpectedFnPathFoundFnKeyword {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "Fn", style = "verbose")]
+    pub fn_token_span: Span,
+}
index 0191ab730c812e89e55099c5896dc4be68284e38..d9fa3e31db97226cdb4bebcf81cb0d24042c3387 100644 (file)
@@ -31,7 +31,8 @@
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
-    fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
+    fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, FatalError, Handler, MultiSpan,
+    PResult,
 };
 use rustc_errors::{pluralize, Diagnostic, ErrorGuaranteed, IntoDiagnostic};
 use rustc_session::errors::ExprParenthesesNeeded;
@@ -41,7 +42,6 @@
 use std::mem::take;
 use std::ops::{Deref, DerefMut};
 use thin_vec::{thin_vec, ThinVec};
-use tracing::{debug, trace};
 
 /// Creates a placeholder argument.
 pub(super) fn dummy_arg(ident: Ident) -> Param {
@@ -1104,7 +1104,11 @@ pub(super) fn check_no_chained_comparison(
                     return if token::ModSep == self.token.kind {
                         // We have some certainty that this was a bad turbofish at this point.
                         // `foo< bar >::`
-                        err.suggest_turbofish = Some(op.span.shrink_to_lo());
+                        if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt {
+                            err.suggest_turbofish = Some(op.span.shrink_to_lo());
+                        } else {
+                            err.help_turbofish = Some(());
+                        }
 
                         let snapshot = self.create_snapshot_for_diagnostic();
                         self.bump(); // `::`
@@ -1130,7 +1134,11 @@ pub(super) fn check_no_chained_comparison(
                     } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
                         // We have high certainty that this was a bad turbofish at this point.
                         // `foo< bar >(`
-                        err.suggest_turbofish = Some(op.span.shrink_to_lo());
+                        if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt {
+                            err.suggest_turbofish = Some(op.span.shrink_to_lo());
+                        } else {
+                            err.help_turbofish = Some(());
+                        }
                         // Consume the fn call arguments.
                         match self.consume_fn_args() {
                             Err(()) => Err(err.into_diagnostic(&self.sess.span_diagnostic)),
@@ -1230,7 +1238,7 @@ pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a
         let sum_span = ty.span.to(self.prev_token.span);
 
         let sub = match &ty.kind {
-            TyKind::Rptr(lifetime, mut_ty) => {
+            TyKind::Ref(lifetime, mut_ty) => {
                 let sum_with_parens = pprust::to_string(|s| {
                     s.s.word("&");
                     s.print_opt_lifetime(lifetime);
@@ -2557,6 +2565,75 @@ pub(crate) fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<
         Ok(())
     }
 
+    pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool {
+        (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
+            && self.look_ahead(3, |tok| tok == short_kind)
+    }
+
+    fn diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
+        if self.is_diff_marker(long_kind, short_kind) {
+            let lo = self.token.span;
+            for _ in 0..4 {
+                self.bump();
+            }
+            return Some(lo.to(self.prev_token.span));
+        }
+        None
+    }
+
+    pub fn recover_diff_marker(&mut self) {
+        let Some(start) = self.diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else {
+            return;
+        };
+        let mut spans = Vec::with_capacity(3);
+        spans.push(start);
+        let mut middlediff3 = None;
+        let mut middle = None;
+        let mut end = None;
+        loop {
+            if self.token.kind == TokenKind::Eof {
+                break;
+            }
+            if let Some(span) = self.diff_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or)) {
+                middlediff3 = Some(span);
+            }
+            if let Some(span) = self.diff_marker(&TokenKind::EqEq, &TokenKind::Eq) {
+                middle = Some(span);
+            }
+            if let Some(span) = self.diff_marker(&TokenKind::BinOp(token::Shr), &TokenKind::Gt) {
+                spans.push(span);
+                end = Some(span);
+                break;
+            }
+            self.bump();
+        }
+        let mut err = self.struct_span_err(spans, "encountered diff marker");
+        err.span_label(start, "after this is the code before the merge");
+        if let Some(middle) = middlediff3 {
+            err.span_label(middle, "");
+        }
+        if let Some(middle) = middle {
+            err.span_label(middle, "");
+        }
+        if let Some(end) = end {
+            err.span_label(end, "above this are the incoming code changes");
+        }
+        err.help(
+            "if you're having merge conflicts after pulling new code, the top section is the code \
+             you already had and the bottom section is the remote code",
+        );
+        err.help(
+            "if you're in the middle of a rebase, the top section is the code being rebased onto \
+             and the bottom section is the code coming from the current commit being rebased",
+        );
+        err.note(
+            "for an explanation on these markers from the `git` documentation, visit \
+             <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
+        );
+        err.emit();
+        FatalError.raise()
+    }
+
     /// Parse and throw away a parenthesized comma separated
     /// sequence of patterns until `)` is reached.
     fn skip_pat_list(&mut self) -> PResult<'a, ()> {
index 6a115088eca61803496212c69e4614b90cec6c31..9f436783ceda6f03fd89c208361f4f767c4e0e61 100644 (file)
@@ -1503,12 +1503,13 @@ fn parse_path_start_expr(&mut self) -> PResult<'a, P<Expr>> {
                 prior_type_ascription: self.last_type_ascription,
             });
             (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
-        } else if self.check(&token::OpenDelim(Delimiter::Brace)) &&
-            let Some(expr) = self.maybe_parse_struct_expr(&qself, &path) {
-                if qself.is_some() {
-                    self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
-                }
-                return expr;
+        } else if self.check(&token::OpenDelim(Delimiter::Brace))
+            && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
+        {
+            if qself.is_some() {
+                self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+            }
+            return expr;
         } else {
             (path.span, ExprKind::Path(qself, path))
         };
@@ -3039,6 +3040,7 @@ fn recover_struct_field_dots(&mut self, close_delim: Delimiter) -> bool {
     /// Parses `ident (COLON expr)?`.
     fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
         let attrs = self.parse_outer_attributes()?;
+        self.recover_diff_marker();
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
 
index 7c2d01509de417b100c281abf1a6863106d05ee0..a958c294930ef4094c2299b080f6bba921b23f30 100644 (file)
@@ -24,7 +24,6 @@
 use rustc_span::DUMMY_SP;
 use std::mem;
 use thin_vec::ThinVec;
-use tracing::debug;
 
 impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
@@ -99,7 +98,9 @@ fn parse_item_(
         fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
+        self.recover_diff_marker();
         let attrs = self.parse_outer_attributes()?;
+        self.recover_diff_marker();
         self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
     }
 
@@ -705,6 +706,7 @@ fn parse_item_list<T>(
             if self.recover_doc_comment_before_brace() {
                 continue;
             }
+            self.recover_diff_marker();
             match parse_item(self) {
                 Ok(None) => {
                     let mut is_unnecessary_semicolon = !items.is_empty()
@@ -1040,8 +1042,11 @@ fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {
     /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
     /// ```
     fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
-        self.parse_delim_comma_seq(Delimiter::Brace, |p| Ok((p.parse_use_tree()?, DUMMY_NODE_ID)))
-            .map(|(r, _)| r)
+        self.parse_delim_comma_seq(Delimiter::Brace, |p| {
+            p.recover_diff_marker();
+            Ok((p.parse_use_tree()?, DUMMY_NODE_ID))
+        })
+        .map(|(r, _)| r)
     }
 
     fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
@@ -1380,7 +1385,9 @@ fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
     }
 
     fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
+        self.recover_diff_marker();
         let variant_attrs = self.parse_outer_attributes()?;
+        self.recover_diff_marker();
         self.collect_tokens_trailing_token(
             variant_attrs,
             ForceCollect::No,
@@ -1574,9 +1581,32 @@ fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<FieldDef>> {
         self.parse_paren_comma_seq(|p| {
             let attrs = p.parse_outer_attributes()?;
             p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| {
+                let mut snapshot = None;
+                if p.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
+                    // Account for `<<<<<<<` diff markers. We can't proactively error here because
+                    // that can be a valid type start, so we snapshot and reparse only we've
+                    // encountered another parse error.
+                    snapshot = Some(p.create_snapshot_for_diagnostic());
+                }
                 let lo = p.token.span;
-                let vis = p.parse_visibility(FollowedByType::Yes)?;
-                let ty = p.parse_ty()?;
+                let vis = match p.parse_visibility(FollowedByType::Yes) {
+                    Ok(vis) => vis,
+                    Err(err) => {
+                        if let Some(ref mut snapshot) = snapshot {
+                            snapshot.recover_diff_marker();
+                        }
+                        return Err(err);
+                    }
+                };
+                let ty = match p.parse_ty() {
+                    Ok(ty) => ty,
+                    Err(err) => {
+                        if let Some(ref mut snapshot) = snapshot {
+                            snapshot.recover_diff_marker();
+                        }
+                        return Err(err);
+                    }
+                };
 
                 Ok((
                     FieldDef {
@@ -1597,7 +1627,9 @@ fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<FieldDef>> {
 
     /// Parses an element of a struct declaration.
     fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
+        self.recover_diff_marker();
         let attrs = self.parse_outer_attributes()?;
+        self.recover_diff_marker();
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
             let vis = this.parse_visibility(FollowedByType::No)?;
@@ -2424,10 +2456,11 @@ pub(super) fn parse_fn_decl(
     }
 
     /// Parses the parameter list of a function, including the `(` and `)` delimiters.
-    fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
+    pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
         let mut first_param = true;
         // Parse the arguments, starting out with `self` being allowed...
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
+            p.recover_diff_marker();
             let param = p.parse_param_general(req_name, first_param).or_else(|mut e| {
                 e.emit();
                 let lo = p.prev_token.span;
@@ -2465,7 +2498,6 @@ fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResu
             };
             let (pat, ty) = if is_name_required || this.is_named_param() {
                 debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
-
                 let (pat, colon) = this.parse_fn_param_pat_colon()?;
                 if !colon {
                     let mut err = this.unexpected::<()>().unwrap_err();
index 40b88788caa6743c66a5e7f9c0e6dba47fd6cb9a..49d3198153953f226f326a211297bc8b54e33f0a 100644 (file)
@@ -317,7 +317,7 @@ fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token
         // required to wrap the text. E.g.
         // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
         // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1)
-        // - `abc "##d##"` is wrapped as `r###"abc "d""###` (num_of_hashes = 3)
+        // - `abc "##d##"` is wrapped as `r###"abc ##"d"##"###` (num_of_hashes = 3)
         let mut num_of_hashes = 0;
         let mut count = 0;
         for ch in data.as_str().chars() {
@@ -1499,6 +1499,10 @@ fn is_import_coupler(&mut self) -> bool {
     pub fn clear_expected_tokens(&mut self) {
         self.expected_tokens.clear();
     }
+
+    pub fn approx_token_stream_pos(&self) -> usize {
+        self.token_cursor.num_next_calls
+    }
 }
 
 pub(crate) fn make_unclosed_delims_error(
index a1981e11477753b4506a5f2770e71570e1eb2c57..0b057f2f577fe73e85489bf75063576cdf3c5d72 100644 (file)
@@ -491,17 +491,6 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
 
         if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
             // The user inverted the order, so help them fix that.
-            let mut applicability = Applicability::MachineApplicable;
-            // FIXME(bindings_after_at): Remove this code when stabilizing the feature.
-            lhs.walk(&mut |p| match p.kind {
-                // `check_match` is unhappy if the subpattern has a binding anywhere.
-                PatKind::Ident(..) => {
-                    applicability = Applicability::MaybeIncorrect;
-                    false // Short-circuit.
-                }
-                _ => true,
-            });
-
             let lhs_span = lhs.span;
             // Move the LHS into the RHS as a subpattern.
             // The RHS is now the full pattern.
@@ -510,7 +499,12 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
             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)
+                .span_suggestion(
+                    sp,
+                    "switch the order",
+                    pprust::pat_to_string(&rhs),
+                    Applicability::MachineApplicable,
+                )
                 .emit();
         } else {
             // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
index bae7f2670cb11689866e837b411160d0cebe7552..0daae457d30224caee7db8d154d93c01537c167e 100644 (file)
@@ -531,13 +531,23 @@ pub(crate) fn parse_block_tail(
         recover: AttemptLocalParseRecovery,
     ) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
+        let mut snapshot = None;
         while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
             if self.token == token::Eof {
                 break;
             }
+            if self.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
+                // Account for `<<<<<<<` diff markers. We can't proactively error here because
+                // that can be a valid path start, so we snapshot and reparse only we've
+                // encountered another parse error.
+                snapshot = Some(self.create_snapshot_for_diagnostic());
+            }
             let stmt = match self.parse_full_stmt(recover) {
                 Err(mut err) if recover.yes() => {
                     self.maybe_annotate_with_ascription(&mut err, false);
+                    if let Some(ref mut snapshot) = snapshot {
+                        snapshot.recover_diff_marker();
+                    }
                     err.emit();
                     self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
                     Some(self.mk_stmt_err(self.token.span))
index b7206b57642fcfaca4bc55feb3fafe2ae727f438..a6f702e5428694aa4077eeae5363c905674c030e 100644 (file)
@@ -1,8 +1,9 @@
 use super::{Parser, PathStyle, TokenType};
 
-use crate::errors::{FnPtrWithGenerics, FnPtrWithGenericsSugg};
+use crate::errors::{ExpectedFnPathFoundFnKeyword, FnPtrWithGenerics, FnPtrWithGenericsSugg};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
+use ast::DUMMY_NODE_ID;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::util::case::Case;
@@ -12,7 +13,9 @@
 };
 use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Symbol;
+use thin_vec::thin_vec;
 
 /// Any `?` or `~const` modifiers that appear at the start of a bound.
 struct BoundModifiers {
@@ -501,7 +504,7 @@ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
             self.bump_with((dyn_tok, dyn_tok_sp));
         }
         let ty = self.parse_ty_no_plus()?;
-        Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
+        Ok(TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }))
     }
 
     // Parses the `typeof(EXPR)`.
@@ -613,6 +616,25 @@ fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) {
     /// 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.
+        if self.token.is_lifetime() {
+            self.look_ahead(1, |t| {
+                if let token::Ident(symname, _) = t.kind {
+                    // parse pattern with "'a Sized" we're supposed to give suggestion like
+                    // "'a + Sized"
+                    self.struct_span_err(
+                        self.token.span,
+                        &format!("expected `+` between lifetime and {}", symname),
+                    )
+                    .span_suggestion_verbose(
+                        self.token.span.shrink_to_hi(),
+                        "add `+`",
+                        " +",
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
+                }
+            })
+        }
         let bounds = self.parse_generic_bounds(None)?;
         *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
         Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
@@ -911,8 +933,20 @@ fn parse_generic_ty_bound(
         has_parens: bool,
         modifiers: BoundModifiers,
     ) -> PResult<'a, GenericBound> {
-        let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-        let path = self.parse_path(PathStyle::Type)?;
+        let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+        let mut path = if self.token.is_keyword(kw::Fn)
+            && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+            && let Some(path) = self.recover_path_from_fn()
+        {
+            path
+        } else {
+            self.parse_path(PathStyle::Type)?
+        };
+
+        if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) {
+            self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
+        }
+
         if has_parens {
             if self.token.is_like_plus() {
                 // Someone has written something like `&dyn (Trait + Other)`. The correct code
@@ -941,6 +975,38 @@ fn parse_generic_ty_bound(
         Ok(GenericBound::Trait(poly_trait, modifier))
     }
 
+    // recovers a `Fn(..)` parenthesized-style path from `fn(..)`
+    fn recover_path_from_fn(&mut self) -> Option<ast::Path> {
+        let fn_token_span = self.token.span;
+        self.bump();
+        let args_lo = self.token.span;
+        let snapshot = self.create_snapshot_for_diagnostic();
+        match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) {
+            Ok(decl) => {
+                self.sess.emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });
+                Some(ast::Path {
+                    span: fn_token_span.to(self.prev_token.span),
+                    segments: thin_vec![ast::PathSegment {
+                        ident: Ident::new(Symbol::intern("Fn"), fn_token_span),
+                        id: DUMMY_NODE_ID,
+                        args: Some(P(ast::GenericArgs::Parenthesized(ast::ParenthesizedArgs {
+                            span: args_lo.to(self.prev_token.span),
+                            inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(),
+                            inputs_span: args_lo.until(decl.output.span()),
+                            output: decl.output.clone(),
+                        }))),
+                    }],
+                    tokens: None,
+                })
+            }
+            Err(diag) => {
+                diag.cancel();
+                self.restore_snapshot(snapshot);
+                None
+            }
+        }
+    }
+
     /// Optionally parses `for<$generic_params>`.
     pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> {
         if self.eat_keyword(kw::For) {
@@ -955,6 +1021,92 @@ pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<Gener
         }
     }
 
+    /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments
+    /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already
+    /// been eaten.
+    fn recover_fn_trait_with_lifetime_params(
+        &mut self,
+        fn_path: &mut ast::Path,
+        lifetime_defs: &mut Vec<GenericParam>,
+    ) -> PResult<'a, ()> {
+        let fn_path_segment = fn_path.segments.last_mut().unwrap();
+        let generic_args = if let Some(p_args) = &fn_path_segment.args {
+            p_args.clone().into_inner()
+        } else {
+            // Normally it wouldn't come here because the upstream should have parsed
+            // generic parameters (otherwise it's impossible to call this function).
+            return Ok(());
+        };
+        let lifetimes =
+            if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) =
+                &generic_args
+            {
+                args.into_iter()
+                    .filter_map(|arg| {
+                        if let ast::AngleBracketedArg::Arg(generic_arg) = arg
+                            && let ast::GenericArg::Lifetime(lifetime) = generic_arg {
+                            Some(lifetime)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect()
+            } else {
+                Vec::new()
+            };
+        // Only try to recover if the trait has lifetime params.
+        if lifetimes.is_empty() {
+            return Ok(());
+        }
+
+        // Parse `(T, U) -> R`.
+        let inputs_lo = self.token.span;
+        let inputs: Vec<_> =
+            self.parse_fn_params(|_| false)?.into_iter().map(|input| input.ty).collect();
+        let inputs_span = inputs_lo.to(self.prev_token.span);
+        let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
+        let args = ast::ParenthesizedArgs {
+            span: fn_path_segment.span().to(self.prev_token.span),
+            inputs,
+            inputs_span,
+            output,
+        }
+        .into();
+        *fn_path_segment =
+            ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID };
+
+        // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`.
+        let mut generic_params = lifetimes
+            .iter()
+            .map(|lt| GenericParam {
+                id: lt.id,
+                ident: lt.ident,
+                attrs: ast::AttrVec::new(),
+                bounds: Vec::new(),
+                is_placeholder: false,
+                kind: ast::GenericParamKind::Lifetime,
+                colon_span: None,
+            })
+            .collect::<Vec<GenericParam>>();
+        lifetime_defs.append(&mut generic_params);
+
+        let generic_args_span = generic_args.span();
+        let mut err =
+            self.struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters");
+        let snippet = format!(
+            "for<{}> ",
+            lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(),
+        );
+        let before_fn_path = fn_path.span.shrink_to_lo();
+        err.multipart_suggestion(
+            "consider using a higher-ranked trait bound instead",
+            vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)],
+            Applicability::MaybeIncorrect,
+        )
+        .emit();
+        Ok(())
+    }
+
     pub(super) fn check_lifetime(&mut self) -> bool {
         self.expected_tokens.push(TokenType::Lifetime);
         self.token.is_lifetime()
index ab0463045faf998ddf7868ff189ba0600a24e42a..1eb227503f24236971e95f3f978f19054b7d9796 100644 (file)
@@ -20,6 +20,7 @@
 pub use Piece::*;
 pub use Position::*;
 
+use rustc_lexer::unescape;
 use std::iter;
 use std::str;
 use std::string;
@@ -56,6 +57,13 @@ pub fn new(position: usize, before: usize, after: usize) -> InnerWidthMapping {
     }
 }
 
+/// Whether the input string is a literal. If yes, it contains the inner width mappings.
+#[derive(Clone, PartialEq, Eq)]
+enum InputStringKind {
+    NotALiteral,
+    Literal { width_mappings: Vec<InnerWidthMapping> },
+}
+
 /// The type of format string that we are parsing.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum ParseMode {
@@ -306,7 +314,11 @@ pub fn new(
         append_newline: bool,
         mode: ParseMode,
     ) -> Parser<'a> {
-        let (width_map, is_literal) = find_width_map_from_snippet(snippet, style);
+        let input_string_kind = find_width_map_from_snippet(s, snippet, style);
+        let (width_map, is_literal) = match input_string_kind {
+            InputStringKind::Literal { width_mappings } => (width_mappings, true),
+            InputStringKind::NotALiteral => (Vec::new(), false),
+        };
         Parser {
             mode,
             input: s,
@@ -435,7 +447,7 @@ fn must_consume(&mut self, c: char) -> Option<usize> {
                 Some(pos)
             } else {
                 let pos = self.to_span_index(pos);
-                let description = format!("expected `'}}'`, found `{:?}`", maybe);
+                let description = format!("expected `'}}'`, found `{maybe:?}`");
                 let label = "expected `}`".to_owned();
                 let (note, secondary_label) = if c == '}' {
                     (
@@ -459,12 +471,12 @@ fn must_consume(&mut self, c: char) -> Option<usize> {
                 None
             }
         } else {
-            let description = format!("expected `{:?}` but string was terminated", c);
+            let description = format!("expected `{c:?}` but string was terminated");
             // point at closing `"`
             let pos = self.input.len() - if self.append_newline { 1 } else { 0 };
             let pos = self.to_span_index(pos);
             if c == '}' {
-                let label = format!("expected `{:?}`", c);
+                let label = format!("expected `{c:?}`");
                 let (note, secondary_label) = if c == '}' {
                     (
                         Some(
@@ -485,7 +497,7 @@ fn must_consume(&mut self, c: char) -> Option<usize> {
                     should_be_replaced_with_positional_argument: false,
                 });
             } else {
-                self.err(description, format!("expected `{:?}`", c), pos.to(pos));
+                self.err(description, format!("expected `{c:?}`"), pos.to(pos));
             }
             None
         }
@@ -844,20 +856,40 @@ fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>)
 /// written code (code snippet) and the `InternedString` that gets processed in the `Parser`
 /// in order to properly synthesise the intra-string `Span`s for error diagnostics.
 fn find_width_map_from_snippet(
+    input: &str,
     snippet: Option<string::String>,
     str_style: Option<usize>,
-) -> (Vec<InnerWidthMapping>, bool) {
+) -> InputStringKind {
     let snippet = match snippet {
         Some(ref s) if s.starts_with('"') || s.starts_with("r\"") || s.starts_with("r#") => s,
-        _ => return (vec![], false),
+        _ => return InputStringKind::NotALiteral,
     };
 
     if str_style.is_some() {
-        return (vec![], true);
+        return InputStringKind::Literal { width_mappings: Vec::new() };
     }
 
+    // Strip quotes.
     let snippet = &snippet[1..snippet.len() - 1];
 
+    // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine
+    // since we will never need to point our spans there, so we lie about it here by ignoring it.
+    // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines.
+    // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up.
+    // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up.
+    let input_no_nl = input.trim_end_matches('\n');
+    let Ok(unescaped) = unescape_string(snippet) else {
+        return InputStringKind::NotALiteral;
+    };
+
+    let unescaped_no_nl = unescaped.trim_end_matches('\n');
+
+    if unescaped_no_nl != input_no_nl {
+        // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect.
+        // This can for example happen with proc macros that respan generated literals.
+        return InputStringKind::NotALiteral;
+    }
+
     let mut s = snippet.char_indices();
     let mut width_mappings = vec![];
     while let Some((pos, c)) = s.next() {
@@ -936,7 +968,21 @@ fn find_width_map_from_snippet(
             _ => {}
         }
     }
-    (width_mappings, true)
+
+    InputStringKind::Literal { width_mappings }
+}
+
+fn unescape_string(string: &str) -> Result<string::String, unescape::EscapeError> {
+    let mut buf = string::String::new();
+    let mut error = Ok(());
+    unescape::unescape_literal(string, unescape::Mode::Str, &mut |_, unescaped_char| {
+        match unescaped_char {
+            Ok(c) => buf.push(c),
+            Err(err) => error = Err(err),
+        }
+    });
+
+    error.map(|_| buf)
 }
 
 // Assert a reasonable size for `Piece`
index 272386f313e8d0736aecdd274652c4374e1fca6e..b86d2316820cec75ab3fa744079775fa22151d6c 100644 (file)
@@ -324,7 +324,7 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
                 Slice,
                 Array,
                 Ptr,
-                Rptr,
+                Ref,
                 BareFn,
                 Never,
                 Tup,
@@ -580,7 +580,7 @@ fn visit_ty(&mut self, t: &'v ast::Ty) {
                 Slice,
                 Array,
                 Ptr,
-                Rptr,
+                Ref,
                 BareFn,
                 Never,
                 Tup,
index 72d38aeac7a0c0647f176fe451143d3cc1611354..8fe47d862e77dc9a329df9abdd960f690068f4b1 100644 (file)
@@ -915,7 +915,7 @@ fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
                     if level != Level::Direct {
                         error_msg.push_str(", ");
                     }
-                    error_msg.push_str(&format!("{:?}: {}", level, vis_str));
+                    error_msg.push_str(&format!("{level:?}: {vis_str}"));
                 }
             } else {
                 error_msg.push_str("not in the table");
@@ -1223,19 +1223,22 @@ fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
                 self.tcx.types.never,
             );
 
-            for (trait_predicate, _, _) in bounds.trait_bounds {
-                if self.visit_trait(trait_predicate.skip_binder()).is_break() {
-                    return;
-                }
-            }
-
-            for (poly_predicate, _) in bounds.projection_bounds {
-                let pred = poly_predicate.skip_binder();
-                let poly_pred_term = self.visit(pred.term);
-                if poly_pred_term.is_break()
-                    || self.visit_projection_ty(pred.projection_ty).is_break()
-                {
-                    return;
+            for (pred, _) in bounds.predicates() {
+                match pred.kind().skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+                        if self.visit_trait(trait_predicate.trait_ref).is_break() {
+                            return;
+                        }
+                    }
+                    ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) => {
+                        let term = self.visit(proj_predicate.term);
+                        if term.is_break()
+                            || self.visit_projection_ty(proj_predicate.projection_ty).is_break()
+                        {
+                            return;
+                        }
+                    }
+                    _ => {}
                 }
             }
         }
@@ -2141,7 +2144,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
             if !old_error_set_ancestry.insert(id) {
                 break;
             }
-            let parent = tcx.hir().get_parent_node(id);
+            let parent = tcx.hir().parent_id(id);
             if parent == id {
                 break;
             }
index b2111a1262a3cd9c82d9e11d7bd53f6ff5cf35dd..46e77626479c83ed7a09df9867c8eac3285674a2 100644 (file)
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [lib]
-doctest = false
+
 
 [dependencies]
 measureme = "10.0.0"
index d426a2b6b78a0655220e6785f4b390a87f0d4b05..2d243e13cc21249a6679d1e298be44dce69c7024 100644 (file)
@@ -34,7 +34,6 @@
 pub use rustc_query_system::query::{deadlock, QueryContext};
 
 pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryVTable;
 
 mod on_disk_cache;
 pub use on_disk_cache::OnDiskCache;
index 2bcfdab03c817bcc983a216d84fa3a78a59e8c92..70c481fb0ee2e0a48d0cb83ac13e85804e7bf157 100644 (file)
@@ -787,7 +787,7 @@ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
         d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || {
-            panic!("Failed to convert DefPathHash {:?}", def_path_hash)
+            panic!("Failed to convert DefPathHash {def_path_hash:?}")
         })
     }
 }
index 9ffcc5672cc33676c2b37077603f21eeff3cb402..6125ad4eff11835e9329ce36c20cdb7f1ce4db35 100644 (file)
@@ -321,7 +321,7 @@ pub(crate) fn create_query_frame<
         ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
     );
     let description =
-        if tcx.sess.verbose() { format!("{} [{:?}]", description, name) } else { description };
+        if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
     let span = if kind == dep_graph::DepKind::def_span {
         // The `def_span` query is used to calculate `default_span`,
         // so exit to avoid infinite recursion.
@@ -493,28 +493,32 @@ fn query_cache<'a>(tcx: QueryCtxt<'tcx>) -> &'a Self::Cache
                 &tcx.query_caches.$name
             }
 
+            fn execute_query(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Stored {
+                tcx.$name(key)
+            }
+
             #[inline]
-            fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
-                QueryVTable<QueryCtxt<'tcx>, Self::Key, Self::Value>
-            {
-                let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
-                let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
-                QueryVTable {
-                    anon: is_anon!([$($modifiers)*]),
-                    eval_always: is_eval_always!([$($modifiers)*]),
-                    depth_limit: depth_limit!([$($modifiers)*]),
-                    feedable: feedable!([$($modifiers)*]),
-                    dep_kind: dep_graph::DepKind::$name,
-                    hash_result: hash_result!([$($modifiers)*]),
-                    handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
-                    compute,
-                    try_load_from_disk: if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None },
-                }
+            // key is only sometimes used
+            #[allow(unused_variables)]
+            fn compute(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> fn(TyCtxt<'tcx>, Self::Key) -> Self::Value {
+                get_provider!([$($modifiers)*][qcx, $name, key])
             }
 
-            fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
-                tcx.$name(k)
+            #[inline]
+            fn try_load_from_disk(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self> {
+                let cache_on_disk = Self::cache_on_disk(qcx.tcx, key);
+                if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None }
             }
+
+            const ANON: bool = is_anon!([$($modifiers)*]);
+            const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+            const DEPTH_LIMIT: bool = depth_limit!([$($modifiers)*]);
+            const FEEDABLE: bool = feedable!([$($modifiers)*]);
+
+            const DEP_KIND: rustc_middle::dep_graph::DepKind = dep_graph::DepKind::$name;
+            const HANDLE_CYCLE_ERROR: rustc_query_system::HandleCycleError = handle_cycle_error!([$($modifiers)*]);
+
+            const HASH_RESULT: rustc_query_system::query::HashResult<QueryCtxt<'tcx>, Self> = hash_result!([$($modifiers)*]);
         })*
 
         #[allow(nonstandard_style)]
index 5f54bab9c31474d87852d7e4fa820a34a385274d..4743170e9bfd8a450f2049e45699e1e4ff44baae 100644 (file)
@@ -111,7 +111,7 @@ impl<T: Debug> IntoSelfProfilingString for T {
         &self,
         builder: &mut QueryKeyStringBuilder<'_, '_>,
     ) -> StringId {
-        let s = format!("{:?}", self);
+        let s = format!("{self:?}");
         builder.profiler.alloc_string(&s[..])
     }
 }
index f9f3169af69c9e5a18465f6133a36196d4f6e7e0..c2c9600f5552cb4a4d7d872c477389ea6986352e 100644 (file)
@@ -29,7 +29,7 @@ pub fn accepts_all(&self) -> bool {
 
     /// Tests whether `node` meets the filter, returning true if so.
     pub fn test<K: DepKind>(&self, node: &DepNode<K>) -> bool {
-        let debug_str = format!("{:?}", node);
+        let debug_str = format!("{node:?}");
         self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f))
     }
 }
@@ -46,7 +46,7 @@ impl<K: DepKind> EdgeFilter<K> {
     pub fn new(test: &str) -> Result<EdgeFilter<K>, Box<dyn Error>> {
         let parts: Vec<_> = test.split("->").collect();
         if parts.len() != 2 {
-            Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into())
+            Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
         } else {
             Ok(EdgeFilter {
                 source: DepNodeFilter::new(parts[0]),
index d79c5816a9c40bb1fc0d3aab18113ae01af46ea8..9e1ca6ab515d846e1f444252dcc4a7ac2ac8120a 100644 (file)
@@ -120,7 +120,7 @@ fn to_fingerprint(&self, _: Tcx) -> Fingerprint {
     }
 
     fn to_debug_str(&self, _: Tcx) -> String {
-        format!("{:?}", self)
+        format!("{self:?}")
     }
 
     /// This method tries to recover the query key from the given `DepNode`,
index 52957ee0222387b62747d335e3429016184cf0bf..53c9da15737183b0120bce2be2d1667e9bb364da 100644 (file)
@@ -316,10 +316,8 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         assert!(
             !self.dep_node_exists(&key),
             "forcing query with already existing `DepNode`\n\
-                 - query-key: {:?}\n\
-                 - dep-node: {:?}",
-            arg,
-            key
+                 - query-key: {arg:?}\n\
+                 - dep-node: {key:?}"
         );
 
         let task_deps = if cx.dep_context().is_eval_always(key.kind) {
@@ -365,8 +363,7 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
             debug_assert!(
                 data.colors.get(prev_index).is_none(),
                 "DepGraph::with_task() - Duplicate DepNodeColor \
-                            insertion for {:?}",
-                key
+                            insertion for {key:?}"
             );
 
             data.colors.insert(prev_index, color);
@@ -447,7 +444,7 @@ pub fn read_index(&self, dep_node_index: DepNodeIndex) {
                     TaskDepsRef::Allow(deps) => deps.lock(),
                     TaskDepsRef::Ignore => return,
                     TaskDepsRef::Forbid => {
-                        panic!("Illegal read of: {:?}", dep_node_index)
+                        panic!("Illegal read of: {dep_node_index:?}")
                     }
                 };
                 let task_deps = &mut *task_deps;
@@ -634,7 +631,7 @@ pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen
         if dep_node_debug.borrow().contains_key(&dep_node) {
             return;
         }
-        let debug_str = debug_str_gen();
+        let debug_str = self.with_ignore(debug_str_gen);
         dep_node_debug.borrow_mut().insert(dep_node, debug_str);
     }
 
@@ -824,12 +821,13 @@ fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
         debug_assert!(
             data.colors.get(prev_dep_node_index).is_none(),
             "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \
-                      insertion for {:?}",
-            dep_node
+                      insertion for {dep_node:?}"
         );
 
         if !side_effects.is_empty() {
-            self.emit_side_effects(qcx, data, dep_node_index, side_effects);
+            self.with_query_deserialization(|| {
+                self.emit_side_effects(qcx, data, dep_node_index, side_effects)
+            });
         }
 
         // ... and finally storing a "Green" entry in the color map.
@@ -1162,7 +1160,7 @@ fn intern_node(
             if let Some(fingerprint) = fingerprint {
                 if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
                     if print_status {
-                        eprintln!("[task::green] {:?}", key);
+                        eprintln!("[task::green] {key:?}");
                     }
 
                     // This is a green node: it existed in the previous compilation,
@@ -1184,7 +1182,7 @@ fn intern_node(
                     (dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
                 } else {
                     if print_status {
-                        eprintln!("[task::red] {:?}", key);
+                        eprintln!("[task::red] {key:?}");
                     }
 
                     // This is a red node: it existed in the previous compilation, its query
@@ -1207,7 +1205,7 @@ fn intern_node(
                 }
             } else {
                 if print_status {
-                    eprintln!("[task::unknown] {:?}", key);
+                    eprintln!("[task::unknown] {key:?}");
                 }
 
                 // This is a red node, effectively: it existed in the previous compilation
@@ -1232,7 +1230,7 @@ fn intern_node(
             }
         } else {
             if print_status {
-                eprintln!("[task::new] {:?}", key);
+                eprintln!("[task::new] {key:?}");
             }
 
             let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
index a918328d4130ea08257536e8f432ca0c42396a32..dfc1344f85c70cabbeb86f452cbd8abc704203dc 100644 (file)
@@ -270,17 +270,14 @@ pub(crate) fn print_incremental_info(
 
             eprintln!("[incremental]");
             eprintln!("[incremental] DepGraph Statistics");
-            eprintln!("{}", SEPARATOR);
+            eprintln!("{SEPARATOR}");
             eprintln!("[incremental]");
             eprintln!("[incremental] Total Node Count: {}", status.total_node_count);
             eprintln!("[incremental] Total Edge Count: {}", status.total_edge_count);
 
             if cfg!(debug_assertions) {
-                eprintln!("[incremental] Total Edge Reads: {}", total_read_count);
-                eprintln!(
-                    "[incremental] Total Duplicate Edge Reads: {}",
-                    total_duplicate_read_count
-                );
+                eprintln!("[incremental] Total Edge Reads: {total_read_count}");
+                eprintln!("[incremental] Total Duplicate Edge Reads: {total_duplicate_read_count}");
             }
 
             eprintln!("[incremental]");
@@ -288,7 +285,7 @@ pub(crate) fn print_incremental_info(
                 "[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
                 "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
             );
-            eprintln!("{}", SEPARATOR);
+            eprintln!("{SEPARATOR}");
 
             for stat in stats {
                 let node_kind_ratio =
@@ -304,7 +301,7 @@ pub(crate) fn print_incremental_info(
                 );
             }
 
-            eprintln!("{}", SEPARATOR);
+            eprintln!("{SEPARATOR}");
             eprintln!("[incremental]");
         }
     }
index 24c960765df8a387b8a177d3a8b4741d13204f3f..8c0330e438de4724711816ed47742d1e5537aee1 100644 (file)
@@ -1,7 +1,6 @@
 //! Query configuration and description traits.
 
-use crate::dep_graph::DepNode;
-use crate::dep_graph::SerializedDepNodeIndex;
+use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
 use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+pub type HashResult<Qcx, Q> =
+    Option<fn(&mut StableHashingContext<'_>, &<Q as QueryConfig<Qcx>>::Value) -> Fingerprint>;
+
+pub type TryLoadFromDisk<Qcx, Q> =
+    Option<fn(Qcx, SerializedDepNodeIndex) -> Option<<Q as QueryConfig<Qcx>>::Value>>;
+
 pub trait QueryConfig<Qcx: QueryContext> {
     const NAME: &'static str;
 
-    type Key: Eq + Hash + Clone + Debug;
+    type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
     type Value: Debug;
     type Stored: Debug + Clone + std::borrow::Borrow<Self::Value>;
 
@@ -30,39 +35,27 @@ fn query_cache<'a>(tcx: Qcx) -> &'a Self::Cache
     where
         Qcx: 'a;
 
-    // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
-
     fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
-}
 
-#[derive(Copy, Clone)]
-pub struct QueryVTable<Qcx: QueryContext, K, V> {
-    pub anon: bool,
-    pub dep_kind: Qcx::DepKind,
-    pub eval_always: bool,
-    pub depth_limit: bool,
-    pub feedable: bool,
-
-    pub compute: fn(Qcx::DepContext, K) -> V,
-    pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
-    pub handle_cycle_error: HandleCycleError,
-    // NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
-    pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
-}
+    fn compute(tcx: Qcx, key: &Self::Key) -> fn(Qcx::DepContext, Self::Key) -> Self::Value;
 
-impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
-    pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
-    where
-        K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
-    {
-        DepNode::construct(tcx, self.dep_kind, key)
-    }
+    fn try_load_from_disk(qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self>;
+
+    const ANON: bool;
+    const EVAL_ALWAYS: bool;
+    const DEPTH_LIMIT: bool;
+    const FEEDABLE: bool;
+
+    const DEP_KIND: Qcx::DepKind;
+    const HANDLE_CYCLE_ERROR: HandleCycleError;
+
+    const HASH_RESULT: HashResult<Qcx, Self>;
 
-    pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
-        (self.compute)(tcx, key)
+    // Just here for convernience and checking that the key matches the kind, don't override this.
+    fn construct_dep_node(tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
+        DepNode::construct(tcx, Self::DEP_KIND, key)
     }
 }
index ce9179ea832e75e8fbc6e61ff2f00b108ae8f1f5..d308af192076051ef23b0098f3375e39791a879a 100644 (file)
@@ -12,7 +12,7 @@
 };
 
 mod config;
-pub use self::config::{QueryConfig, QueryVTable};
+pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk};
 
 use crate::dep_graph::DepKind;
 use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
index 53844dab9db59490992e073f0b62bf742df3f223..b3b939eae88dce04c1e1efa8bb3a6bcc19a9910a 100644 (file)
@@ -2,10 +2,9 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex};
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
-use crate::query::config::QueryVTable;
 use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
 use crate::values::Value;
@@ -361,36 +360,34 @@ pub fn try_get_cached<Tcx, C, R, OnHit>(
     })
 }
 
-fn try_execute_query<Qcx, C>(
+fn try_execute_query<Q, Qcx>(
     qcx: Qcx,
-    state: &QueryState<C::Key, Qcx::DepKind>,
-    cache: &C,
+    state: &QueryState<Q::Key, Qcx::DepKind>,
+    cache: &Q::Cache,
     span: Span,
-    key: C::Key,
+    key: Q::Key,
     dep_node: Option<DepNode<Qcx::DepKind>>,
-    query: &QueryVTable<Qcx, C::Key, C::Value>,
-) -> (C::Stored, Option<DepNodeIndex>)
+) -> (Q::Stored, Option<DepNodeIndex>)
 where
-    C: QueryCache,
-    C::Key: Clone + DepNodeParams<Qcx::DepContext>,
-    C::Value: Value<Qcx::DepContext, Qcx::DepKind>,
-    C::Stored: Debug + std::borrow::Borrow<C::Value>,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    match JobOwner::<'_, C::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
+    match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) = execute_job(qcx, key.clone(), dep_node, query, job.id);
-            if query.feedable {
+            let (result, dep_node_index) =
+                execute_job::<Q, Qcx>(qcx, key.clone(), dep_node, job.id);
+            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, _| {
-                    let hasher = query.hash_result.expect("feedable forbids no_hash");
+                    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));
                     debug_assert_eq!(
                         old_hash, new_hash,
                         "Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}",
-                        query.dep_kind, key, result, cached_result,
+                        Q::DEP_KIND, key, result, cached_result,
                     );
                 });
             }
@@ -398,7 +395,7 @@ fn try_execute_query<Qcx, C>(
             (result, Some(dep_node_index))
         }
         TryGetJob::Cycle(error) => {
-            let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
+            let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
             (result, None)
         }
         #[cfg(parallel_compiler)]
@@ -417,16 +414,14 @@ fn try_execute_query<Qcx, C>(
     }
 }
 
-fn execute_job<Qcx, K, V>(
+fn execute_job<Q, Qcx>(
     qcx: Qcx,
-    key: K,
+    key: Q::Key,
     mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
-    query: &QueryVTable<Qcx, K, V>,
     job_id: QueryJobId,
-) -> (V, DepNodeIndex)
+) -> (Q::Value, DepNodeIndex)
 where
-    K: Clone + DepNodeParams<Qcx::DepContext>,
-    V: Debug,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
     let dep_graph = qcx.dep_context().dep_graph();
@@ -434,23 +429,23 @@ fn execute_job<Qcx, K, V>(
     // Fast path for when incr. comp. is off.
     if !dep_graph.is_fully_enabled() {
         let prof_timer = qcx.dep_context().profiler().query_provider();
-        let result = qcx.start_query(job_id, query.depth_limit, None, || {
-            query.compute(*qcx.dep_context(), key)
+        let result = qcx.start_query(job_id, Q::DEPTH_LIMIT, None, || {
+            Q::compute(qcx, &key)(*qcx.dep_context(), key)
         });
         let dep_node_index = dep_graph.next_virtual_depnode_index();
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
         return (result, dep_node_index);
     }
 
-    if !query.anon && !query.eval_always {
+    if !Q::ANON && !Q::EVAL_ALWAYS {
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
-            dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
+            dep_node_opt.get_or_insert_with(|| Q::construct_dep_node(*qcx.dep_context(), &key));
 
         // The diagnostics for this query will be promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
         if let Some(ret) = qcx.start_query(job_id, false, None, || {
-            try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
+            try_load_from_disk_and_cache_in_memory::<Q, Qcx>(qcx, &key, &dep_node)
         }) {
             return ret;
         }
@@ -460,18 +455,19 @@ fn execute_job<Qcx, K, V>(
     let diagnostics = Lock::new(ThinVec::new());
 
     let (result, dep_node_index) =
-        qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
-            if query.anon {
-                return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
-                    query.compute(*qcx.dep_context(), key)
+        qcx.start_query(job_id, Q::DEPTH_LIMIT, Some(&diagnostics), || {
+            if Q::ANON {
+                return dep_graph.with_anon_task(*qcx.dep_context(), Q::DEP_KIND, || {
+                    Q::compute(qcx, &key)(*qcx.dep_context(), key)
                 });
             }
 
             // `to_dep_node` is expensive for some `DepKind`s.
             let dep_node =
-                dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
+                dep_node_opt.unwrap_or_else(|| Q::construct_dep_node(*qcx.dep_context(), &key));
 
-            dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
+            let task = Q::compute(qcx, &key);
+            dep_graph.with_task(dep_node, *qcx.dep_context(), key, task, Q::HASH_RESULT)
         });
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -480,7 +476,7 @@ fn execute_job<Qcx, K, V>(
     let side_effects = QuerySideEffects { diagnostics };
 
     if std::intrinsics::unlikely(!side_effects.is_empty()) {
-        if query.anon {
+        if Q::ANON {
             qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
         } else {
             qcx.store_side_effects(dep_node_index, side_effects);
@@ -490,16 +486,14 @@ fn execute_job<Qcx, K, V>(
     (result, dep_node_index)
 }
 
-fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
     qcx: Qcx,
-    key: &K,
+    key: &Q::Key,
     dep_node: &DepNode<Qcx::DepKind>,
-    query: &QueryVTable<Qcx, K, V>,
-) -> Option<(V, DepNodeIndex)>
+) -> Option<(Q::Value, DepNodeIndex)>
 where
-    K: Clone,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
-    V: Debug,
 {
     // Note this function can be called concurrently from the same query
     // We must ensure that this is handled correctly.
@@ -511,7 +505,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
 
     // First we try to load the result from the on-disk cache.
     // Some things are never cached on disk.
-    if let Some(try_load_from_disk) = query.try_load_from_disk {
+    if let Some(try_load_from_disk) = Q::try_load_from_disk(qcx, &key) {
         let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
 
         // The call to `with_query_deserialization` enforces that no new `DepNodes`
@@ -545,7 +539,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
             if std::intrinsics::unlikely(
                 try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
             ) {
-                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
             }
 
             return Some((result, dep_node_index));
@@ -555,8 +549,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
         // can be forced from `DepNode`.
         debug_assert!(
             !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
-            "missing on-disk cache entry for {:?}",
-            dep_node
+            "missing on-disk cache entry for {dep_node:?}"
         );
     }
 
@@ -565,7 +558,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
     let prof_timer = qcx.dep_context().profiler().query_provider();
 
     // The dep-graph for this computation is already in-place.
-    let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
+    let result = dep_graph.with_ignore(|| Q::compute(qcx, key)(*qcx.dep_context(), key.clone()));
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -578,7 +571,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
     //
     // See issue #82920 for an example of a miscompilation that would get turned into
     // an ICE by this check
-    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
 
     Some((result, dep_node_index))
 }
@@ -595,8 +588,7 @@ pub(crate) fn incremental_verify_ich<Tcx, V: Debug>(
 {
     assert!(
         tcx.dep_graph().is_green(dep_node),
-        "fingerprint for green query instance not loaded from cache: {:?}",
-        dep_node,
+        "fingerprint for green query instance not loaded from cache: {dep_node:?}",
     );
 
     let new_hash = hash_result.map_or(Fingerprint::ZERO, |f| {
@@ -675,16 +667,16 @@ fn incremental_verify_ich_failed(sess: &Session, dep_node: DebugArg<'_>, result:
         sess.emit_err(crate::error::Reentrant);
     } else {
         let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
-            format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+            format!("`cargo clean -p {crate_name}` or `cargo clean`")
         } else {
             "`cargo clean`".to_string()
         };
 
         sess.emit_err(crate::error::IncrementCompilation {
             run_cmd,
-            dep_node: format!("{:?}", dep_node),
+            dep_node: format!("{dep_node:?}"),
         });
-        panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
+        panic!("Found unstable fingerprints for {dep_node:?}: {result:?}");
     }
 
     INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
@@ -699,23 +691,19 @@ fn incremental_verify_ich_failed(sess: &Session, dep_node: DebugArg<'_>, result:
 ///
 /// Note: The optimization is only available during incr. comp.
 #[inline(never)]
-fn ensure_must_run<Qcx, K, V>(
-    qcx: Qcx,
-    key: &K,
-    query: &QueryVTable<Qcx, K, V>,
-) -> (bool, Option<DepNode<Qcx::DepKind>>)
+fn ensure_must_run<Q, Qcx>(qcx: Qcx, key: &Q::Key) -> (bool, Option<DepNode<Qcx::DepKind>>)
 where
-    K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    if query.eval_always {
+    if Q::EVAL_ALWAYS {
         return (true, None);
     }
 
     // Ensuring an anonymous query makes no sense
-    assert!(!query.anon);
+    assert!(!Q::ANON);
 
-    let dep_node = query.to_dep_node(*qcx.dep_context(), key);
+    let dep_node = Q::construct_dep_node(*qcx.dep_context(), key);
 
     let dep_graph = qcx.dep_context().dep_graph();
     match dep_graph.try_mark_green(qcx, &dep_node) {
@@ -746,13 +734,11 @@ pub fn get_query<Q, Qcx, D>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode)
 where
     D: DepKind,
     Q: QueryConfig<Qcx>,
-    Q::Key: DepNodeParams<Qcx::DepContext>,
     Q::Value: Value<Qcx::DepContext, D>,
     Qcx: QueryContext,
 {
-    let query = Q::make_vtable(qcx, &key);
     let dep_node = if let QueryMode::Ensure = mode {
-        let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
+        let (must_run, dep_node) = ensure_must_run::<Q, _>(qcx, &key);
         if !must_run {
             return None;
         }
@@ -761,14 +747,13 @@ pub fn get_query<Q, Qcx, D>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode)
         None
     };
 
-    let (result, dep_node_index) = try_execute_query(
+    let (result, dep_node_index) = try_execute_query::<Q, Qcx>(
         qcx,
         Q::query_state(qcx),
         Q::query_cache(qcx),
         span,
         key,
         dep_node,
-        &query,
     );
     if let Some(dep_node_index) = dep_node_index {
         qcx.dep_context().dep_graph().read_index(dep_node_index)
@@ -780,7 +765,6 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
 where
     D: DepKind,
     Q: QueryConfig<Qcx>,
-    Q::Key: DepNodeParams<Qcx::DepContext>,
     Q::Value: Value<Qcx::DepContext, D>,
     Qcx: QueryContext,
 {
@@ -798,9 +782,8 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
         Err(()) => {}
     }
 
-    let query = Q::make_vtable(qcx, &key);
     let state = Q::query_state(qcx);
-    debug_assert!(!query.anon);
+    debug_assert!(!Q::ANON);
 
-    try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+    try_execute_query::<Q, _>(qcx, state, cache, DUMMY_SP, key, Some(dep_node));
 }
index 0c4b35b88335ad5e429b68d74e14db5555fb3451..e41fe325b811cb42cf118565782a00e1f75df0eb 100644 (file)
@@ -820,13 +820,12 @@ fn resolve_ident_in_module_unadjusted_ext(
             // binding if it exists. What we really want here is having two separate scopes in
             // a module - one for non-globs and one for globs, but until that's done use this
             // hack to avoid inconsistent resolution ICEs during import validation.
-            let binding = [resolution.binding, resolution.shadowed_glob]
-                .into_iter()
-                .filter_map(|binding| match (binding, ignore_binding) {
+            let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map(
+                |binding| match (binding, ignore_binding) {
                     (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
                     _ => binding,
-                })
-                .next();
+                },
+            );
             let Some(binding) = binding else {
                 return Err((Determined, Weak::No));
             };
index 5b7a00101e9b75b53cd635ec29c1d90da6a9a5be..ca43762aa214ec63c846c738a8a8aabe90d86e64 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg};
+use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
@@ -536,6 +536,9 @@ struct DiagnosticMetadata<'ast> {
     in_assignment: Option<&'ast Expr>,
     is_assign_rhs: bool,
 
+    /// Used to detect possible `.` -> `..` typo when calling methods.
+    in_range: Option<(&'ast Expr, &'ast Expr)>,
+
     /// If we are currently in a trait object definition. Used to point at the bounds when
     /// encountering a struct or enum.
     current_trait_object: Option<&'ast [ast::GenericBound]>,
@@ -648,7 +651,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
         let prev = self.diagnostic_metadata.current_trait_object;
         let prev_ty = self.diagnostic_metadata.current_type_path;
         match ty.kind {
-            TyKind::Rptr(None, _) => {
+            TyKind::Ref(None, _) => {
                 // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
                 // NodeId `ty.id`.
                 // This span will be used in case of elision failure.
@@ -1512,7 +1515,7 @@ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
             count: 1,
         };
         let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
-        for rib in self.lifetime_ribs.iter().rev() {
+        for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
             debug!(?rib.kind);
             match rib.kind {
                 LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
@@ -1529,16 +1532,31 @@ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
                     } else {
                         ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
                     };
-                    rustc_errors::struct_span_err!(
+                    let mut diag = rustc_errors::struct_span_err!(
                         self.r.session,
                         lifetime.ident.span,
                         E0637,
                         "{}",
                         msg,
-                    )
-                    .span_label(lifetime.ident.span, note)
-                    .emit();
-
+                    );
+                    diag.span_label(lifetime.ident.span, note);
+                    if elided {
+                        for rib in self.lifetime_ribs[i..].iter().rev() {
+                            if let LifetimeRibKind::Generics {
+                                span,
+                                kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound,
+                                ..
+                            } = &rib.kind
+                            {
+                                diag.span_help(
+                                    *span,
+                                    "consider introducing a higher-ranked lifetime here with `for<'a>`",
+                                );
+                                break;
+                            }
+                        }
+                    }
+                    diag.emit();
                     self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
                     return;
                 }
@@ -2001,7 +2019,7 @@ fn is_self_ty(&self, ty: &Ty) -> bool {
         impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
             fn visit_ty(&mut self, ty: &'a Ty) {
                 trace!("SelfVisitor considering ty={:?}", ty);
-                if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
+                if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
                     let lt_id = if let Some(lt) = lt {
                         lt.id
                     } else {
@@ -3320,6 +3338,7 @@ fn smart_resolve_path(
         );
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn smart_resolve_path_fragment(
         &mut self,
         qself: &Option<P<QSelf>>,
@@ -3327,10 +3346,6 @@ fn smart_resolve_path_fragment(
         source: PathSource<'ast>,
         finalize: Finalize,
     ) -> PartialRes {
-        debug!(
-            "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})",
-            qself, path, finalize,
-        );
         let ns = source.namespace();
 
         let Finalize { node_id, path_span, .. } = finalize;
@@ -3341,8 +3356,28 @@ fn smart_resolve_path_fragment(
 
                 let def_id = this.parent_scope.module.nearest_parent_mod();
                 let instead = res.is_some();
-                let suggestion =
-                    if res.is_none() { this.report_missing_type_error(path) } else { None };
+                let suggestion = if let Some((start, end)) = this.diagnostic_metadata.in_range
+                    && path[0].ident.span.lo() == end.span.lo()
+                {
+                    let mut sugg = ".";
+                    let mut span = start.span.between(end.span);
+                    if span.lo() + BytePos(2) == span.hi() {
+                        // There's no space between the start, the range op and the end, suggest
+                        // removal which will look better.
+                        span = span.with_lo(span.lo() + BytePos(1));
+                        sugg = "";
+                    }
+                    Some((
+                        span,
+                        "you might have meant to write `.` instead of `..`",
+                        sugg.to_string(),
+                        Applicability::MaybeIncorrect,
+                    ))
+                } else if res.is_none() {
+                    this.report_missing_type_error(path)
+                } else {
+                    None
+                };
 
                 this.r.use_injections.push(UseError {
                     err,
@@ -4005,6 +4040,12 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
                 self.visit_expr(rhs);
                 self.diagnostic_metadata.is_assign_rhs = false;
             }
+            ExprKind::Range(Some(ref start), Some(ref end), RangeLimits::HalfOpen) => {
+                self.diagnostic_metadata.in_range = Some((start, end));
+                self.resolve_expr(start, Some(expr));
+                self.resolve_expr(end, Some(expr));
+                self.diagnostic_metadata.in_range = None;
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
index 600308b6508db9931c3b6974acf48493421d8bfc..74522f185422d45eb948d01335284ff0e457427b 100644 (file)
@@ -1554,7 +1554,7 @@ fn lookup_assoc_candidate<FilterFn>(
         fn extract_node_id(t: &Ty) -> Option<NodeId> {
             match t.kind {
                 TyKind::Path(None, _) => Some(t.id),
-                TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
+                TyKind::Ref(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
                 // This doesn't handle the remaining `Ty` variants as they are not
                 // that commonly the self_type, it might be interesting to provide
                 // support for those in future.
@@ -2189,7 +2189,7 @@ pub(crate) fn maybe_report_lifetime_uses(
                 Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
                     debug!(?param.ident, ?param.ident.span, ?use_span);
 
-                    let elidable = matches!(use_ctxt, LifetimeCtxt::Rptr);
+                    let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
 
                     let deletion_span = deletion_span();
                     self.r.lint_buffer.buffer_lint_with_diagnostic(
index 6afd5fe5a7f2a1a9e96b9f2d5d10c5a74427ac92..a8d82de02b7548836d5b8e3a7e70ae07caab06a2 100644 (file)
@@ -600,7 +600,7 @@ pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
                 if seg.res != Res::Err {
                     seg.res
                 } else {
-                    let parent_node = self.tcx.hir().get_parent_node(hir_id);
+                    let parent_node = self.tcx.hir().parent_id(hir_id);
                     self.get_path_res(parent_node)
                 }
             }
index 9197a28c1888309481d8fbf19e8322c946199831..5a1bcb8fdc87be9a82047dbed9040ee4e3c17afd 100644 (file)
@@ -165,7 +165,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 let text = format!("{}{}", prefix, nested.text);
                 Ok(replace_text(nested, text))
             }
-            hir::TyKind::Rptr(ref lifetime, ref mt) => {
+            hir::TyKind::Ref(ref lifetime, ref mt) => {
                 let mut prefix = "&".to_owned();
                 prefix.push_str(&lifetime.ident.to_string());
                 prefix.push(' ');
index 3bafd3730bd79d2db4cb31d95bda50d7e756a492..1ccfc59f7a9d61e86b5b9f245cf0f8303f465e6b 100644 (file)
@@ -35,6 +35,7 @@
 use std::iter;
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
+use std::sync::LazyLock;
 
 pub mod sigpipe;
 
@@ -554,6 +555,16 @@ pub enum PrintRequest {
     SplitDebuginfo,
 }
 
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum TraitSolver {
+    /// Classic trait solver in `rustc_trait_selection::traits::select`
+    Classic,
+    /// Chalk trait solver
+    Chalk,
+    /// Experimental trait solver in `rustc_trait_selection::solve`
+    Next,
+}
+
 pub enum Input {
     /// Load source code from a file.
     File(PathBuf),
@@ -787,6 +798,12 @@ pub fn share_generics(&self) -> bool {
     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
         self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
     }
+
+    #[allow(rustc::bad_opt_access)]
+    pub fn incremental_relative_spans(&self) -> bool {
+        self.unstable_opts.incremental_relative_spans
+            || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
+    }
 }
 
 impl UnstableOptions {
@@ -1306,7 +1323,12 @@ pub fn multi(a: S, b: S, c: S, d: S) -> R {
         unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
     }
 }
-
+static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
+    format!(
+        "Specify which edition of the compiler to use when compiling code. \
+The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
+    )
+});
 /// Returns the "short" subset of the rustc command line options,
 /// including metadata for each option, such as whether the option is
 /// part of the stable long-term interface for rustc.
@@ -1339,7 +1361,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
         opt::opt_s(
             "",
             "edition",
-            "Specify which edition of the compiler to use when compiling code.",
+            &*EDITION_STRING,
             EDITION_NAME_LIST,
         ),
         opt::multi_s(
@@ -2755,7 +2777,7 @@ pub(crate) mod dep_tracking {
         BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
         InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
         OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
-        SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
+        SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -2855,6 +2877,7 @@ fn hash(
         BranchProtection,
         OomStrategy,
         LanguageIdentifier,
+        TraitSolver,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
@@ -2975,3 +2998,21 @@ pub enum ProcMacroExecutionStrategy {
     /// Run the proc-macro code on a different thread.
     CrossThread,
 }
+
+/// Which format to use for `-Z dump-mono-stats`
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum DumpMonoStatsFormat {
+    /// Pretty-print a markdown table
+    Markdown,
+    /// Emit structured JSON
+    Json,
+}
+
+impl DumpMonoStatsFormat {
+    pub fn extension(self) -> &'static str {
+        match self {
+            Self::Markdown => "md",
+            Self::Json => "json",
+        }
+    }
+}
index e72b76cfee9e9660a427746e2cadd14cb0ef711c..f5a72573d58cd00d8d1cc5c4fbafb5e6ed0e9333 100644 (file)
@@ -260,9 +260,11 @@ pub(crate) struct InvalidFloatLiteralSuffix {
 
 #[derive(Diagnostic)]
 #[diag(session_int_literal_too_large)]
+#[note]
 pub(crate) struct IntLiteralTooLarge {
     #[primary_span]
     pub span: Span,
+    pub limit: String,
 }
 
 #[derive(Diagnostic)]
@@ -361,8 +363,15 @@ fn fix_base_capitalisation(prefix: &str, suffix: &str) -> Option<String> {
                 _ => unreachable!(),
             };
         }
-        LitError::IntTooLarge => {
-            sess.emit_err(IntLiteralTooLarge { span });
+        LitError::IntTooLarge(base) => {
+            let max = u128::MAX;
+            let limit = match base {
+                2 => format!("{max:#b}"),
+                8 => format!("{max:#o}"),
+                16 => format!("{max:#x}"),
+                _ => format!("{max}"),
+            };
+            sess.emit_err(IntLiteralTooLarge { span, limit });
         }
     }
 }
index ae01efebacc21e9f4ffc41ef8a25e6b07a93f871..043a60a1c5310c7247ad0fe286c681d7269d2226 100644 (file)
@@ -377,10 +377,13 @@ mod desc {
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
     pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
+    pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
     pub const parse_instrument_coverage: &str =
         "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
     pub const parse_unpretty: &str = "`string` or `string=string`";
     pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
+    pub const parse_trait_solver: &str =
+        "one of the supported solver modes (`classic`, `chalk`, or `next`)";
     pub const parse_lto: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
     pub const parse_linker_plugin_lto: &str =
@@ -820,6 +823,21 @@ pub(crate) fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>
         true
     }
 
+    pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
+        match v {
+            None => true,
+            Some("json") => {
+                *slot = DumpMonoStatsFormat::Json;
+                true
+            }
+            Some("markdown") => {
+                *slot = DumpMonoStatsFormat::Markdown;
+                true
+            }
+            Some(_) => false,
+        }
+    }
+
     pub(crate) fn parse_instrument_coverage(
         slot: &mut Option<InstrumentCoverage>,
         v: Option<&str>,
@@ -864,6 +882,18 @@ pub(crate) fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<
         }
     }
 
+    pub(crate) fn parse_trait_solver(slot: &mut TraitSolver, v: Option<&str>) -> bool {
+        match v {
+            Some("classic") => *slot = TraitSolver::Classic,
+            Some("chalk") => *slot = TraitSolver::Chalk,
+            Some("next") => *slot = TraitSolver::Next,
+            // default trait solver is subject to change..
+            Some("default") => *slot = TraitSolver::Classic,
+            _ => return false,
+        }
+        true
+    }
+
     pub(crate) fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
         if v.is_some() {
             let mut bool_arg = None;
@@ -1233,8 +1263,6 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "instrument control-flow architecture protection"),
     cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
         "the codegen unit partitioning strategy to use"),
-    chalk: bool = (false, parse_bool, [TRACKED],
-        "enable the experimental Chalk-based trait solving engine"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
     combine_cgu: bool = (false, parse_bool, [TRACKED],
@@ -1295,7 +1323,9 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         an additional `.html` file showing the computed coverage spans."),
     dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
         parse_switch_with_opt_path, [UNTRACKED],
-        "output statistics about monomorphization collection (format: markdown)"),
+        "output statistics about monomorphization collection"),
+    dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
+        "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
     dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     dylib_lto: bool = (false, parse_bool, [UNTRACKED],
@@ -1332,11 +1362,12 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "generate human-readable, predictable names for codegen units (default: no)"),
     identify_regions: bool = (false, parse_bool, [UNTRACKED],
         "display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
-    incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
+    incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
         "ignore spans during ICH computation -- used for testing (default: no)"),
     incremental_info: bool = (false, parse_bool, [UNTRACKED],
         "print high-level information about incremental reuse (or the lack thereof) \
         (default: no)"),
+    #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
     incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
         "hash spans relative to their parent item for incr. comp. (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
@@ -1590,6 +1621,8 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "for every macro invocation, print its name and arguments (default: no)"),
     track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "tracks where in rustc a diagnostic was emitted"),
+    trait_solver: TraitSolver = (TraitSolver::Classic, parse_trait_solver, [TRACKED],
+        "specify the trait solver mode used by rustc (default: classic)"),
     // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
     // alongside query results and changes to translation options can affect diagnostics - so
     // translation options should be tracked.
index 4a3d29414d6e598f2b24efe90835e626f916b34a..1b2e8d9dc707bdd60673f4b2d859057899227588 100644 (file)
@@ -590,7 +590,19 @@ pub fn span_warn_with_code<S: Into<MultiSpan>>(
     pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
         self.diagnostic().warn(msg)
     }
-    /// Delay a span_bug() call until abort_if_errors()
+
+    /// Ensures that compilation cannot succeed.
+    ///
+    /// If this function has been called but no errors have been emitted and
+    /// compilation succeeds, it will cause an internal compiler error (ICE).
+    ///
+    /// This can be used in code paths that should never run on successful compilations.
+    /// For example, it can be used to create an [`ErrorGuaranteed`]
+    /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission directly).
+    ///
+    /// If no span is available, use [`DUMMY_SP`].
+    ///
+    /// [`DUMMY_SP`]: rustc_span::DUMMY_SP
     #[track_caller]
     pub fn delay_span_bug<S: Into<MultiSpan>>(
         &self,
index 221f65b66e6d4b77a1a0f63bc27acf3905e718b5..7c5e1427d1ed72e9e7a8f45ad2c2e70cb8eef90e 100644 (file)
@@ -303,7 +303,7 @@ pub fn expect_local(self) -> LocalDefId {
         // i.e. don't use closures.
         match self.as_local() {
             Some(local_def_id) => local_def_id,
-            None => panic!("DefId::expect_local: `{:?}` isn't local", self),
+            None => panic!("DefId::expect_local: `{self:?}` isn't local"),
         }
     }
 
index 065d3660e5008955269305b45450874886d8a7f2..b43183916bca542bcf7a7092a0583ce75f339dbe 100644 (file)
@@ -44,7 +44,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             Edition::Edition2021 => "2021",
             Edition::Edition2024 => "2024",
         };
-        write!(f, "{}", s)
+        write!(f, "{s}")
     }
 }
 
index c2d8287f2431dc3faa5cad0a1b0070e97257dc72..a9a9a3fbf9d8061c54dbd6fc05d8894d0a339da7 100644 (file)
@@ -104,9 +104,13 @@ fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str)
         // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
         // which will cause us to require that this method always be called with `Span` hashing
         // enabled.
+        //
+        // Span hashing can also be disabled without `-Z incremental-ignore-spans`.
+        // This is the case for instance when building a hash for name mangling.
+        // Such configuration must not be used for metadata.
         HashingControls { hash_spans }
             if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {}
-        other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
+        other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
     }
 }
 
@@ -316,6 +320,7 @@ pub fn expansion_cause(mut self) -> Option<Span> {
             // Stop going up the backtrace once include! is encountered
             if expn_data.is_root()
                 || expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
+                || expn_data.kind == ExpnKind::Inlined
             {
                 break;
             }
@@ -624,7 +629,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb
 pub fn debug_hygiene_data(verbose: bool) -> String {
     HygieneData::with(|data| {
         if verbose {
-            format!("{:#?}", data)
+            format!("{data:#?}")
         } else {
             let mut s = String::from("Expansions:");
             let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
@@ -1062,9 +1067,9 @@ pub fn descr(&self) -> String {
         match *self {
             ExpnKind::Root => kw::PathRoot.to_string(),
             ExpnKind::Macro(macro_kind, name) => match macro_kind {
-                MacroKind::Bang => format!("{}!", name),
-                MacroKind::Attr => format!("#[{}]", name),
-                MacroKind::Derive => format!("#[derive({})]", name),
+                MacroKind::Bang => format!("{name}!"),
+                MacroKind::Attr => format!("#[{name}]"),
+                MacroKind::Derive => format!("#[derive({name})]"),
             },
             ExpnKind::AstPass(kind) => kind.descr().to_string(),
             ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
@@ -1461,11 +1466,7 @@ impl<D: Decoder> Decodable<D> for SyntaxContext {
 /// collisions are only possible between `ExpnId`s within the same crate.
 fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
     // This disambiguator should not have been set yet.
-    assert_eq!(
-        expn_data.disambiguator, 0,
-        "Already set disambiguator for ExpnData: {:?}",
-        expn_data
-    );
+    assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
     assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
     let mut expn_hash = expn_data.hash_expn(&mut ctx);
 
index 2181c090027b535819aec1eb8afeb1851c0f4841..7e61f2f9f73c0a3d5c27ceb4eb3fe2d457558b5b 100644 (file)
@@ -329,7 +329,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
             ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
             CfgSpec(_) => write!(fmt, "<cfgspec>"),
             CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
-            Custom(ref s) => write!(fmt, "<{}>", s),
+            Custom(ref s) => write!(fmt, "<{s}>"),
             DocTest(ref path, _) => write!(fmt, "{}", path.display()),
             InlineAsm(_) => write!(fmt, "<inline asm>"),
         }
@@ -796,6 +796,9 @@ pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
 
     /// Returns a `Span` that would enclose both `self` and `end`.
     ///
+    /// Note that this can also be used to extend the span "backwards":
+    /// `start.to(end)` and `end.to(start)` return the same `Span`.
+    ///
     /// ```text
     ///     ____             ___
     ///     self lorem ipsum end
@@ -1071,7 +1074,7 @@ fn new(pos: BytePos, width: usize) -> Self {
             0 => NonNarrowChar::ZeroWidth(pos),
             2 => NonNarrowChar::Wide(pos),
             4 => NonNarrowChar::Tab(pos),
-            _ => panic!("width {} given for non-narrow character", width),
+            _ => panic!("width {width} given for non-narrow character"),
         }
     }
 
index f169007fab43d77ff58d09d7168049706d2fee08..0ab890b9f01217ca2693b0fd97e1af4488603589 100644 (file)
@@ -27,7 +27,7 @@ fn record_arg_with_span<A>(&mut self, event_arg: A, span: crate::Span)
             if let Some(source_map) = &*session_globals.source_map.borrow() {
                 source_map.span_to_embeddable_string(span)
             } else {
-                format!("{:?}", span)
+                format!("{span:?}")
             }
         });
         self.record_arg(span_arg);
index d9c87ac0ba82bfb6ecb0c9b3991dc6dee752ea44..fa09b4faa441f3b83d50809c92b426e708784b89 100644 (file)
@@ -964,45 +964,40 @@ pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<us
 
     /// Finds the width of the character, either before or after the end of provided span,
     /// depending on the `forwards` parameter.
+    #[instrument(skip(self, sp))]
     fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         let sp = sp.data();
 
         if sp.lo == sp.hi && !forwards {
-            debug!("find_width_of_character_at_span: early return empty span");
+            debug!("early return empty span");
             return 1;
         }
 
         let local_begin = self.lookup_byte_offset(sp.lo);
         let local_end = self.lookup_byte_offset(sp.hi);
-        debug!(
-            "find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`",
-            local_begin, local_end
-        );
+        debug!("local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end);
 
         if local_begin.sf.start_pos != local_end.sf.start_pos {
-            debug!("find_width_of_character_at_span: begin and end are in different files");
+            debug!("begin and end are in different files");
             return 1;
         }
 
         let start_index = local_begin.pos.to_usize();
         let end_index = local_end.pos.to_usize();
-        debug!(
-            "find_width_of_character_at_span: start_index=`{:?}`, end_index=`{:?}`",
-            start_index, end_index
-        );
+        debug!("start_index=`{:?}`, end_index=`{:?}`", start_index, end_index);
 
         // Disregard indexes that are at the start or end of their spans, they can't fit bigger
         // characters.
         if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) {
-            debug!("find_width_of_character_at_span: start or end of span, cannot be multibyte");
+            debug!("start or end of span, cannot be multibyte");
             return 1;
         }
 
         let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
-        debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
+        debug!("source_len=`{:?}`", source_len);
         // Ensure indexes are also not malformed.
         if start_index > end_index || end_index > source_len - 1 {
-            debug!("find_width_of_character_at_span: source indexes are malformed");
+            debug!("source indexes are malformed");
             return 1;
         }
 
@@ -1017,10 +1012,10 @@ fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         } else {
             return 1;
         };
-        debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
+        debug!("snippet=`{:?}`", snippet);
 
         let mut target = if forwards { end_index + 1 } else { end_index - 1 };
-        debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
+        debug!("initial target=`{:?}`", target);
 
         while !snippet.is_char_boundary(target - start_index) && target < source_len {
             target = if forwards {
@@ -1033,9 +1028,9 @@ fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
                     }
                 }
             };
-            debug!("find_width_of_character_at_span: target=`{:?}`", target);
+            debug!("target=`{:?}`", target);
         }
-        debug!("find_width_of_character_at_span: final target=`{:?}`", target);
+        debug!("final target=`{:?}`", target);
 
         if forwards { (target - end_index) as u32 } else { (end_index - target) as u32 }
     }
index f0e91e5a6a917c3373fa399a2e496fe243ab805d..d48c4f7e5a8119f1c84f2a9b32d043dcab05e898 100644 (file)
@@ -4,7 +4,7 @@
 // The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
 // See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
 
-use crate::def_id::LocalDefId;
+use crate::def_id::{DefIndex, LocalDefId};
 use crate::hygiene::SyntaxContext;
 use crate::SPAN_TRACK;
 use crate::{BytePos, SpanData};
@@ -13,8 +13,8 @@
 
 /// A compressed span.
 ///
-/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length and
+/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
+/// is a form that only takes up 8 bytes, with less space for the length, parent and
 /// context. The vast majority (99.9%+) of `SpanData` instances will fit within
 /// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
 /// stored in a separate interner table, and the `Span` will index into that
@@ -25,7 +25,7 @@
 /// slower because only 80--90% of spans could be stored inline (even less in
 /// very large crates) and so the interner was used a lot more.
 ///
-/// Inline (compressed) format:
+/// Inline (compressed) format with no parent:
 /// - `span.base_or_index == span_data.lo`
 /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
 /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
 /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
 /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
+/// Inline (compressed) format with root context:
+/// - `span.base_or_index == span_data.lo`
+/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
+/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+///
 /// Interned format:
 /// - `span.base_or_index == index` (indexes into the interner table)
 /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
@@ -73,7 +79,8 @@ pub struct Span {
     ctxt_or_tag: u16,
 }
 
-const LEN_TAG: u16 = 0b1000_0000_0000_0000;
+const LEN_TAG: u16 = 0b1111_1111_1111_1111;
+const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
 const MAX_LEN: u32 = 0b0111_1111_1111_1111;
 const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
 const MAX_CTXT: u32 = CTXT_TAG - 1;
@@ -95,16 +102,32 @@ pub fn new(
 
         let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
 
-        if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
-            // Inline format.
-            Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
-        } else {
-            // Interned format.
-            let index =
-                with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
-            let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
-            Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+        if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+            let len_or_tag = len as u16;
+            debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+
+            if let Some(parent) = parent {
+                // Inline format with parent.
+                let len_or_tag = len_or_tag | PARENT_MASK;
+                let parent2 = parent.local_def_index.as_u32();
+                if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+                    return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
+                }
+            } else {
+                // Inline format with ctxt.
+                return Span {
+                    base_or_index: base,
+                    len_or_tag: len as u16,
+                    ctxt_or_tag: ctxt2 as u16,
+                };
+            }
         }
+
+        // Interned format.
+        let index =
+            with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
+        let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+        Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
     }
 
     #[inline]
@@ -122,12 +145,25 @@ pub fn data(self) -> SpanData {
     pub fn data_untracked(self) -> SpanData {
         if self.len_or_tag != LEN_TAG {
             // Inline format.
-            debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
-            SpanData {
-                lo: BytePos(self.base_or_index),
-                hi: BytePos(self.base_or_index + self.len_or_tag as u32),
-                ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
-                parent: None,
+            if self.len_or_tag & PARENT_MASK == 0 {
+                debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+                SpanData {
+                    lo: BytePos(self.base_or_index),
+                    hi: BytePos(self.base_or_index + self.len_or_tag as u32),
+                    ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+                    parent: None,
+                }
+            } else {
+                let len = self.len_or_tag & !PARENT_MASK;
+                debug_assert!(len as u32 <= MAX_LEN);
+                let parent =
+                    LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+                SpanData {
+                    lo: BytePos(self.base_or_index),
+                    hi: BytePos(self.base_or_index + len as u32),
+                    ctxt: SyntaxContext::root(),
+                    parent: Some(parent),
+                }
             }
         } else {
             // Interned format.
@@ -141,8 +177,14 @@ pub fn data_untracked(self) -> SpanData {
     pub fn ctxt(self) -> SyntaxContext {
         let ctxt_or_tag = self.ctxt_or_tag as u32;
         if ctxt_or_tag <= MAX_CTXT {
-            // Inline format or interned format with inline ctxt.
-            SyntaxContext::from_u32(ctxt_or_tag)
+            if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
+                // Inline format or interned format with inline ctxt.
+                SyntaxContext::from_u32(ctxt_or_tag)
+            } else {
+                // Inline format or interned format with inline parent.
+                // We know that the SyntaxContext is root.
+                SyntaxContext::root()
+            }
         } else {
             // Interned format.
             let index = self.base_or_index;
index 90f654c68ecbf1d9969144c5e3c59631309fbfad..5d5f8d6d65405c5fd00d57f741d95c39dd12b4a7 100644 (file)
         FromIterator,
         FromResidual,
         Future,
+        FutureOutput,
         FxHashMap,
         FxHashSet,
         GlobalAlloc,
         Is,
         ItemContext,
         Iterator,
+        IteratorItem,
         Layout,
         Left,
         LinkedList,
index a59c9011ab21a4116e4452b206392781e0ab0e25..23ff6b333f0dd7626a397f3c1445e27a058e063e 100644 (file)
@@ -175,7 +175,7 @@ fn finalize_pending_component(&mut self) {
     fn finish(mut self, hash: u64) -> String {
         self.finalize_pending_component();
         // E = end name-sequence
-        let _ = write!(self.result, "17h{:016x}E", hash);
+        let _ = write!(self.result, "17h{hash:016x}E");
         self.result
     }
 }
@@ -227,7 +227,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
                 self = self.print_type(ty)?;
                 self.write_str("; ")?;
                 if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
-                    write!(self, "{}", size)?
+                    write!(self, "{size}")?
                 } else if let ty::ConstKind::Param(param) = size.kind() {
                     self = param.print(self)?
                 } else {
index 62f44a48032efd93301b704bf538bdea53813c8f..547a5907660236f130ce94ea3d7a2ace3536d30c 100644 (file)
@@ -269,8 +269,7 @@ fn compute_symbol_name<'tcx>(
 
     debug_assert!(
         rustc_demangle::try_demangle(&symbol).is_ok(),
-        "compute_symbol_name: `{}` cannot be demangled",
-        symbol
+        "compute_symbol_name: `{symbol}` cannot be demangled"
     );
 
     symbol
index 150459ce0f53181898bbdf09d1f793abbc0a5762..c6899f8f244ef929d536b951ef969a25093aae3e 100644 (file)
@@ -74,7 +74,7 @@ fn process_attrs(&mut self, def_id: LocalDefId) {
                 tcx.sess.emit_err(TestOutput {
                     span: attr.span,
                     kind: Kind::DemanglingAlt,
-                    content: format!("{:#}", demangling),
+                    content: format!("{demangling:#}"),
                 });
             }
         }
index 493e31a688fccdf6f6c0a4a19d1811faa763969a..0759b95bd94c8f5e4d930f7d5f50224ef30e5611 100644 (file)
@@ -126,11 +126,11 @@ fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T)
         if value < zero {
             s.push('n')
         };
-        let _ = write!(s, "{}", value);
+        let _ = write!(s, "{value}");
     }
 
     fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
-        let _ = write!(s, "{}", value);
+        let _ = write!(s, "{value}");
     }
 
     if let Some(scalar_int) = c.kind().try_to_scalar_int() {
@@ -164,6 +164,7 @@ fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
 
 /// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
 /// Rust types that are not used at the FFI boundary.
+#[instrument(level = "trace", skip(tcx, dict))]
 fn encode_fnsig<'tcx>(
     tcx: TyCtxt<'tcx>,
     fn_sig: &FnSig<'tcx>,
@@ -653,6 +654,7 @@ fn encode_ty<'tcx>(
 // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
 // c_void types into unit types unconditionally, and generalizes all pointers if
 // TransformTyOptions::GENERALIZE_POINTERS option is set.
+#[instrument(level = "trace", skip(tcx))]
 fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
     let mut ty = ty;
 
@@ -698,7 +700,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     !is_zst
                 });
                 if let Some(field) = field {
-                    let ty0 = tcx.type_of(field.did);
+                    let ty0 = tcx.bound_type_of(field.did).subst(tcx, substs);
                     // Generalize any repr(transparent) user-defined type that is either a pointer
                     // or reference, and either references itself or any other type that contains or
                     // references itself, to avoid a reference cycle.
@@ -827,6 +829,7 @@ fn transform_substs<'tcx>(
 
 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
 /// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+#[instrument(level = "trace", skip(tcx))]
 pub fn typeid_for_fnabi<'tcx>(
     tcx: TyCtxt<'tcx>,
     fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
index 4285aa62cb96307991169be15b067839e36c2686..0d446d654dc5ce99ede511fb1a4c6f7fc149f279 100644 (file)
@@ -206,6 +206,7 @@ fn in_binder<'a, T>(
     where
         T: TypeVisitable<'tcx>,
     {
+        // FIXME(non-lifetime-binders): What to do here?
         let regions = if value.has_late_bound_regions() {
             self.tcx.collect_referenced_late_bound_regions(value)
         } else {
@@ -609,7 +610,7 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
                     bits = val.unsigned_abs();
                 }
 
-                let _ = write!(self.out, "{:x}_", bits);
+                let _ = write!(self.out, "{bits:x}_");
             }
 
             // FIXME(valtrees): Remove the special case for `str`
@@ -637,7 +638,7 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
 
                                 // FIXME(eddyb) use a specialized hex-encoding loop.
                                 for byte in s.bytes() {
-                                    let _ = write!(self.out, "{:02x}", byte);
+                                    let _ = write!(self.out, "{byte:02x}");
                                 }
 
                                 self.push("_");
index a5ffaebea0b98cb76986ac4a1bfc2530d2035d3c..3b8c867d35ba37b3a06e41b64b90123c19f514d6 100644 (file)
@@ -71,12 +71,7 @@ pub struct ArgAttribute: u16 {
             const NonNull   = 1 << 3;
             const ReadOnly  = 1 << 4;
             const InReg     = 1 << 5;
-            // Due to past miscompiles in LLVM, we use a separate attribute for
-            // &mut arguments, so that the codegen backend can decide whether
-            // or not to actually emit the attribute. It can also be controlled
-            // with the `-Zmutable-noalias` debugging option.
-            const NoAliasMutRef = 1 << 6;
-            const NoUndef = 1 << 7;
+            const NoUndef = 1 << 6;
         }
     }
 }
@@ -177,12 +172,12 @@ pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
                 17..=32 => dl.i32_align.abi,
                 33..=64 => dl.i64_align.abi,
                 65..=128 => dl.i128_align.abi,
-                _ => panic!("unsupported integer: {:?}", self),
+                _ => panic!("unsupported integer: {self:?}"),
             },
             RegKind::Float => match self.size.bits() {
                 32 => dl.f32_align.abi,
                 64 => dl.f64_align.abi,
-                _ => panic!("unsupported float: {:?}", self),
+                _ => panic!("unsupported float: {self:?}"),
             },
             RegKind::Vector => dl.vector_align(self.size).abi,
         }
@@ -642,7 +637,7 @@ impl fmt::Display for AdjustForForeignAbiError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::Unsupported { arch, abi } => {
-                write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
+                write!(f, "target architecture {arch:?} does not support `extern {abi}` ABI")
             }
         }
     }
@@ -760,7 +755,7 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
             "AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
             "AvrInterrupt" => Ok(Conv::AvrInterrupt),
             "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
-            _ => Err(format!("'{}' is not a valid value for entry function call convetion.", s)),
+            _ => Err(format!("'{s}' is not a valid value for entry function call convetion.")),
         }
     }
 }
index 62a0f9fb03470129e369ec2830e2690c0369268e..28493c7700ffca27cb77fb5b0f0c5343ff5d6cc2 100644 (file)
@@ -195,6 +195,6 @@ pub fn emit(
             (modifier.unwrap_or('v'), self as u32 - Self::v0 as u32)
         };
         assert!(index < 32);
-        write!(out, "{}{}", prefix, index)
+        write!(out, "{prefix}{index}")
     }
 }
index 0db3eb6fcac0cc69605d9779e4a91169d7c13aae..ec7429a306554c868c8d8f28ce804a9bb72904e6 100644 (file)
@@ -249,7 +249,7 @@ pub fn emit(
             let index = self as u32 - Self::q0 as u32;
             assert!(index < 16);
             let index = index * 2 + (modifier == 'f') as u32;
-            write!(out, "d{}", index)
+            write!(out, "d{index}")
         } else {
             out.write_str(self.name())
         }
index 65d2cd64bf69319c9b2e1e06924c1d0cfc697c5e..7f01f33d39c6cace7bfcb13e9fccd35963ae45f1 100644 (file)
@@ -679,13 +679,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             Self::I128 => f.write_str("i128"),
             Self::F32 => f.write_str("f32"),
             Self::F64 => f.write_str("f64"),
-            Self::VecI8(n) => write!(f, "i8x{}", n),
-            Self::VecI16(n) => write!(f, "i16x{}", n),
-            Self::VecI32(n) => write!(f, "i32x{}", n),
-            Self::VecI64(n) => write!(f, "i64x{}", n),
-            Self::VecI128(n) => write!(f, "i128x{}", n),
-            Self::VecF32(n) => write!(f, "f32x{}", n),
-            Self::VecF64(n) => write!(f, "f64x{}", n),
+            Self::VecI8(n) => write!(f, "i8x{n}"),
+            Self::VecI16(n) => write!(f, "i16x{n}"),
+            Self::VecI32(n) => write!(f, "i32x{n}"),
+            Self::VecI64(n) => write!(f, "i64x{n}"),
+            Self::VecI128(n) => write!(f, "i128x{n}"),
+            Self::VecF32(n) => write!(f, "f32x{n}"),
+            Self::VecF64(n) => write!(f, "f64x{n}"),
         }
     }
 }
index 238c365093f085aa19d4bfd897398f33bae0f1ce..5eae07f141fc00b515cc8256cb6a7593fea3bbf3 100644 (file)
@@ -357,28 +357,28 @@ pub fn emit(
         if self as u32 <= Self::dx as u32 {
             let root = ['a', 'b', 'c', 'd'][self as usize - Self::ax as usize];
             match modifier.unwrap_or(reg_default_modifier) {
-                'l' => write!(out, "{}l", root),
-                'h' => write!(out, "{}h", root),
-                'x' => write!(out, "{}x", root),
-                'e' => write!(out, "e{}x", root),
-                'r' => write!(out, "r{}x", root),
+                'l' => write!(out, "{root}l"),
+                'h' => write!(out, "{root}h"),
+                'x' => write!(out, "{root}x"),
+                'e' => write!(out, "e{root}x"),
+                'r' => write!(out, "r{root}x"),
                 _ => unreachable!(),
             }
         } else if self as u32 <= Self::di as u32 {
             let root = self.name();
             match modifier.unwrap_or(reg_default_modifier) {
-                'l' => write!(out, "{}l", root),
-                'x' => write!(out, "{}", root),
-                'e' => write!(out, "e{}", root),
-                'r' => write!(out, "r{}", root),
+                'l' => write!(out, "{root}l"),
+                'x' => write!(out, "{root}"),
+                'e' => write!(out, "e{root}"),
+                'r' => write!(out, "r{root}"),
                 _ => unreachable!(),
             }
         } else if self as u32 <= Self::r15 as u32 {
             let root = self.name();
             match modifier.unwrap_or(reg_default_modifier) {
-                'l' => write!(out, "{}b", root),
-                'x' => write!(out, "{}w", root),
-                'e' => write!(out, "{}d", root),
+                'l' => write!(out, "{root}b"),
+                'x' => write!(out, "{root}w"),
+                'e' => write!(out, "{root}d"),
                 'r' => out.write_str(root),
                 _ => unreachable!(),
             }
@@ -387,15 +387,15 @@ pub fn emit(
         } else if self as u32 <= Self::xmm15 as u32 {
             let prefix = modifier.unwrap_or('x');
             let index = self as u32 - Self::xmm0 as u32;
-            write!(out, "{}{}", prefix, index)
+            write!(out, "{prefix}{index}")
         } else if self as u32 <= Self::ymm15 as u32 {
             let prefix = modifier.unwrap_or('y');
             let index = self as u32 - Self::ymm0 as u32;
-            write!(out, "{}{}", prefix, index)
+            write!(out, "{prefix}{index}")
         } else if self as u32 <= Self::zmm31 as u32 {
             let prefix = modifier.unwrap_or('z');
             let index = self as u32 - Self::zmm0 as u32;
-            write!(out, "{}{}", prefix, index)
+            write!(out, "{prefix}{index}")
         } else {
             out.write_str(self.name())
         }
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
deleted file mode 100644 (file)
index 4634433..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-use crate::spec::{SanitizerSet, Target, TargetOptions};
-
-pub fn target() -> Target {
-    Target {
-        llvm_target: "aarch64-fuchsia".into(),
-        pointer_width: 64,
-        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
-        arch: "aarch64".into(),
-        options: TargetOptions {
-            max_atomic_width: Some(128),
-            supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI,
-            ..super::fuchsia_base::opts()
-        },
-    }
-}
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_unknown_fuchsia.rs
new file mode 100644 (file)
index 0000000..ef2ab30
--- /dev/null
@@ -0,0 +1,17 @@
+use crate::spec::{SanitizerSet, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "aarch64-unknown-fuchsia".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            max_atomic_width: Some(128),
+            supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::CFI
+                | SanitizerSet::SHADOWCALLSTACK,
+            ..super::fuchsia_base::opts()
+        },
+    }
+}
index 44644c4733e8726b33c886394631744352af4a04..5c6dcc0aba9c354e8c3dc6ad8b398050935436c3 100644 (file)
@@ -76,7 +76,7 @@ fn target_cpu(self) -> &'static str {
 
 fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
     let platform_name: StaticCow<str> = match abi {
-        "sim" => format!("{}-simulator", os).into(),
+        "sim" => format!("{os}-simulator").into(),
         "macabi" => "mac-catalyst".into(),
         _ => os.into(),
     };
@@ -193,7 +193,7 @@ fn macos_deployment_target(arch: Arch) -> (u32, u32) {
 
 fn macos_lld_platform_version(arch: Arch) -> String {
     let (major, minor) = macos_deployment_target(arch);
-    format!("{}.{}", major, minor)
+    format!("{major}.{minor}")
 }
 
 pub fn macos_llvm_target(arch: Arch) -> String {
@@ -252,7 +252,7 @@ pub fn ios_llvm_target(arch: Arch) -> String {
 
 fn ios_lld_platform_version() -> String {
     let (major, minor) = ios_deployment_target();
-    format!("{}.{}", major, minor)
+    format!("{major}.{minor}")
 }
 
 pub fn ios_sim_llvm_target(arch: Arch) -> String {
@@ -266,7 +266,7 @@ fn tvos_deployment_target() -> (u32, u32) {
 
 fn tvos_lld_platform_version() -> String {
     let (major, minor) = tvos_deployment_target();
-    format!("{}.{}", major, minor)
+    format!("{major}.{minor}")
 }
 
 fn watchos_deployment_target() -> (u32, u32) {
@@ -275,7 +275,7 @@ fn watchos_deployment_target() -> (u32, u32) {
 
 fn watchos_lld_platform_version() -> String {
     let (major, minor) = watchos_deployment_target();
-    format!("{}.{}", major, minor)
+    format!("{major}.{minor}")
 }
 
 pub fn watchos_sim_llvm_target(arch: Arch) -> String {
diff --git a/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
new file mode 100644 (file)
index 0000000..ebd2cca
--- /dev/null
@@ -0,0 +1,40 @@
+use crate::abi::Endian;
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+/// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib).
+///
+/// Requires the VITASDK toolchain on the host system.
+
+pub fn target() -> Target {
+    let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,-q"]);
+
+    Target {
+        llvm_target: "armv7a-vita-newlibeabihf".into(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+
+        options: TargetOptions {
+            os: "vita".into(),
+            endian: Endian::Little,
+            c_int_width: "32".into(),
+            dynamic_linking: false,
+            env: "newlib".into(),
+            vendor: "sony".into(),
+            abi: "eabihf".into(),
+            linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+            no_default_libraries: false,
+            cpu: "cortex-a9".into(),
+            executables: true,
+            families: cvs!["unix"],
+            linker: Some("arm-vita-eabi-gcc".into()),
+            relocation_model: RelocModel::Static,
+            features: "+v7,+neon".into(),
+            pre_link_args,
+            exe_suffix: ".elf".into(),
+            panic_strategy: PanicStrategy::Abort,
+            max_atomic_width: Some(32),
+            ..Default::default()
+        },
+    }
+}
index baf36587147a690d4ecbeba0066468e4f5af6c2f..2b00cda44b511372a33ba51c89c95eb721fcd249 100644 (file)
@@ -6,7 +6,7 @@ pub fn opts(endian: Endian) -> TargetOptions {
         allow_asm: true,
         endian,
         linker_flavor: LinkerFlavor::Bpf,
-        atomic_cas: false,
+        atomic_cas: true,
         dynamic_linking: true,
         no_builtins: true,
         panic_strategy: PanicStrategy::Abort,
@@ -19,6 +19,10 @@ pub fn opts(endian: Endian) -> TargetOptions {
         obj_is_bitcode: true,
         requires_lto: false,
         singlethread: true,
+        // When targeting the `v3` cpu in llvm, 32-bit atomics are also supported.
+        // But making this value change based on the target cpu can be mostly confusing
+        // and would require a bit of a refactor.
+        min_atomic_width: Some(64),
         max_atomic_width: Some(64),
         ..Default::default()
     }
index 4512db49403d73602628c40dd6469c99cc58ae25..0fafa52a45b66aa155323f8835b23f7031adf75f 100644 (file)
@@ -840,7 +840,7 @@ impl fmt::Display for SanitizerSet {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut first = true;
         for s in *self {
-            let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {:?}", s));
+            let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {s:?}"));
             if !first {
                 f.write_str(", ")?;
             }
@@ -1109,8 +1109,8 @@ fn $module() {
     ("x86_64-apple-darwin", x86_64_apple_darwin),
     ("i686-apple-darwin", i686_apple_darwin),
 
-    ("aarch64-fuchsia", aarch64_fuchsia),
-    ("x86_64-fuchsia", x86_64_fuchsia),
+    ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
+    ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
 
     ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
 
@@ -1241,6 +1241,8 @@ fn $module() {
 
     ("aarch64-nintendo-switch-freestanding", aarch64_nintendo_switch_freestanding),
 
+    ("armv7-sony-vita-newlibeabihf", armv7_sony_vita_newlibeabihf),
+
     ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi),
     ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
 
@@ -2072,7 +2074,7 @@ pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
         let mut get_req_field = |name: &str| {
             obj.remove(name)
                 .and_then(|j| j.as_str().map(str::to_string))
-                .ok_or_else(|| format!("Field {} in target specification is required", name))
+                .ok_or_else(|| format!("Field {name} in target specification is required"))
         };
 
         let mut base = Target {
@@ -2478,7 +2480,7 @@ macro_rules! key {
             if let Some(s) = fp.as_str() {
                 base.frame_pointer = s
                     .parse()
-                    .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
+                    .map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?;
             } else {
                 incorrect_type.push("frame-pointer".into())
             }
@@ -2670,7 +2672,7 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
                     return load_file(&p);
                 }
 
-                Err(format!("Could not find specification for target {:?}", target_triple))
+                Err(format!("Could not find specification for target {target_triple:?}"))
             }
             TargetTriple::TargetJson { ref contents, .. } => {
                 let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
@@ -2934,7 +2936,7 @@ pub fn from_path(path: &Path) -> Result<Self, io::Error> {
         let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
             io::Error::new(
                 io::ErrorKind::InvalidInput,
-                format!("target path {:?} is not a valid file: {}", canonicalized_path, err),
+                format!("target path {canonicalized_path:?} is not a valid file: {err}"),
             )
         })?;
         let triple = canonicalized_path
@@ -2969,7 +2971,7 @@ pub fn debug_triple(&self) -> String {
                 let mut hasher = DefaultHasher::new();
                 content.hash(&mut hasher);
                 let hash = hasher.finish();
-                format!("{}-{}", triple, hash)
+                format!("{triple}-{hash}")
             }
         }
     }
index c585a6cd58ea20885a84d1d719a5de3d0a78e774..eaf72b7616c7160ee6d01ec9fd52e27c34e475e7 100644 (file)
@@ -3,7 +3,7 @@
 
 pub fn opts(kernel: &str) -> TargetOptions {
     TargetOptions {
-        os: format!("solid_{}", kernel).into(),
+        os: format!("solid_{kernel}").into(),
         vendor: "kmc".into(),
         executables: false,
         frame_pointer: FramePointer::NonLeaf,
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
deleted file mode 100644 (file)
index 532dd6d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target};
-
-pub fn target() -> Target {
-    let mut base = super::fuchsia_base::opts();
-    base.cpu = "x86-64".into();
-    base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::X86;
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
-
-    Target {
-        llvm_target: "x86_64-fuchsia".into(),
-        pointer_width: 64,
-        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-            .into(),
-        arch: "x86_64".into(),
-        options: base,
-    }
-}
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_unknown_fuchsia.rs
new file mode 100644 (file)
index 0000000..a3231d1
--- /dev/null
@@ -0,0 +1,18 @@
+use crate::spec::{SanitizerSet, StackProbeType, Target};
+
+pub fn target() -> Target {
+    let mut base = super::fuchsia_base::opts();
+    base.cpu = "x86-64".into();
+    base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::X86;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
+
+    Target {
+        llvm_target: "x86_64-unknown-fuchsia".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .into(),
+        arch: "x86_64".into(),
+        options: base,
+    }
+}
index 6c70bbf75163a83348a12cd5ca8415abf1a7e7e8..50c1787ef8c3d20ea323d5151a0493ffd749aa0c 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::arena::ArenaAllocatable;
-use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
+use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
 use rustc_middle::traits::query::Fallible;
 use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable};
 use rustc_middle::ty::{GenericArg, ToPredicate};
@@ -102,7 +102,7 @@ fn enter_canonical_trait_query<K, R>(
         &mut self,
         canonical_key: &Canonical<'tcx, K>,
         operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
+    ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
     where
         K: TypeFoldable<'tcx>,
         R: Debug + TypeFoldable<'tcx>,
@@ -130,7 +130,7 @@ fn enter_canonical_trait_query<K, R>(
         &mut self,
         canonical_key: &Canonical<'tcx, K>,
         operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
+    ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
     where
         K: TypeFoldable<'tcx>,
         R: Debug + TypeFoldable<'tcx>,
index 8d73a83aec96e119639b011ab134ff94176f964c..fdd6adb681be4cba1aa43187d323db65e864b3b4 100644 (file)
@@ -36,7 +36,7 @@ pub(super) fn did_overflow(&self) -> bool {
 
     #[inline]
     pub(super) fn has_overflow(&self, depth: usize) -> bool {
-        self.current_limit.value_within_limit(depth + self.additional_depth)
+        !self.current_limit.value_within_limit(depth + self.additional_depth)
     }
 
     /// Updating the current limit when hitting overflow.
index f8efe9bfa9f827b3d98c2544ebb544d73849e339..71fb6058cd2c54e722a0be82f736dd295f7b9ceb 100644 (file)
@@ -168,24 +168,27 @@ struct Visitor<'a, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
 
         infcx: &'a InferCtxt<'tcx>,
+        single_match: Option<Result<ty::Const<'tcx>, ()>>,
     }
+
     impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
         type BreakTy = ();
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!("is_const_evaluatable: candidate={:?}", c);
-            if let Ok(()) = self.infcx.commit_if_ok(|_| {
+            if self.infcx.probe(|_| {
                 let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
-                if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
-                    && let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
+                ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok()
+                    && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
                     && ocx.select_all_or_error().is_empty()
-                {
-                    Ok(())
-                } else {
-                    Err(())
-                }
             }) {
-                ControlFlow::BREAK
-            } else if let ty::ConstKind::Expr(e) = c.kind() {
+                self.single_match = match self.single_match {
+                    None => Some(Ok(c)),
+                    Some(Ok(o)) if o == c => Some(Ok(c)),
+                    Some(_) => Some(Err(())),
+                };
+            }
+
+            if let ty::ConstKind::Expr(e) = c.kind() {
                 e.visit_with(self)
             } else {
                 // FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s substs.
@@ -200,22 +203,29 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
     }
 
+    let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
+
     for pred in param_env.caller_bounds() {
         match pred.kind().skip_binder() {
             ty::PredicateKind::ConstEvaluatable(ce) => {
                 let b_ct = tcx.expand_abstract_consts(ce);
-                let mut v = Visitor { ct, infcx, param_env };
-                let result = b_ct.visit_with(&mut v);
+                let mut v = Visitor { ct, infcx, param_env, single_match };
+                let _ = b_ct.visit_with(&mut v);
 
-                if let ControlFlow::Break(()) = result {
-                    debug!("is_const_evaluatable: yes");
-                    return true;
-                }
+                single_match = v.single_match;
             }
             _ => {} // don't care
         }
     }
 
+    if let Some(Ok(c)) = single_match {
+        let ocx = ObligationCtxt::new(infcx);
+        assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok());
+        assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
+        assert!(ocx.select_all_or_error().is_empty());
+        return true;
+    }
+
     debug!("is_const_evaluatable: no");
     false
 }
index c028e89e4ea2963f093b48240a8f98ca613199d3..369f80139a806c7fb00b02de7a8caf8fd4cd0919 100644 (file)
@@ -3,12 +3,13 @@
 
 use super::TraitEngine;
 use super::{ChalkFulfillmentContext, FulfillmentContext};
+use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
 use crate::traits::NormalizeExt;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::{
-    Canonical, CanonicalVarValues, CanonicalizedQueryResponse, QueryResponse,
+    Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
 use rustc_infer::infer::{InferCtxt, InferOk};
 use rustc_infer::traits::query::Fallible;
@@ -20,6 +21,7 @@
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::TraitSolver;
 use rustc_span::Span;
 
 pub trait TraitEngineExt<'tcx> {
@@ -29,18 +31,18 @@ pub trait TraitEngineExt<'tcx> {
 
 impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
-        if tcx.sess.opts.unstable_opts.chalk {
-            Box::new(ChalkFulfillmentContext::new())
-        } else {
-            Box::new(FulfillmentContext::new())
+        match tcx.sess.opts.unstable_opts.trait_solver {
+            TraitSolver::Classic => Box::new(FulfillmentContext::new()),
+            TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()),
+            TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
         }
     }
 
     fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
-        if tcx.sess.opts.unstable_opts.chalk {
-            Box::new(ChalkFulfillmentContext::new_in_snapshot())
-        } else {
-            Box::new(FulfillmentContext::new_in_snapshot())
+        match tcx.sess.opts.unstable_opts.trait_solver {
+            TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()),
+            TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()),
+            TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
         }
     }
 }
@@ -213,7 +215,7 @@ pub fn make_canonicalized_query_response<T>(
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+    ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
     where
         T: Debug + TypeFoldable<'tcx>,
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
index 8f317beaa77dd15c32a76fb0656ca732d8d1f3ae..9c098e1a2fc12b6beaee3ce595e38a714b367a41 100644 (file)
 use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
     self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
     TypeVisitable,
 };
+use rustc_session::config::TraitSolver;
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::sym;
@@ -770,7 +771,11 @@ fn report_selection_error(
                                 ),
                             }
                         };
-
+                        self.check_for_binding_assigned_block_without_tail_expression(
+                            &obligation,
+                            &mut err,
+                            trait_predicate,
+                        );
                         if self.suggest_add_reference_to_arg(
                             &obligation,
                             &mut err,
@@ -868,6 +873,11 @@ fn report_selection_error(
                             );
                         }
 
+                        if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
+                            err.emit();
+                            return;
+                        }
+
                         if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
                             err.emit();
                             return;
@@ -1167,7 +1177,7 @@ fn report_selection_error(
                     }
 
                     ty::PredicateKind::WellFormed(ty) => {
-                        if !self.tcx.sess.opts.unstable_opts.chalk {
+                        if self.tcx.sess.opts.unstable_opts.trait_solver == TraitSolver::Classic {
                             // WF predicates cannot themselves make
                             // errors. They can only block due to
                             // ambiguity; otherwise, they always
@@ -1179,7 +1189,7 @@ fn report_selection_error(
                             // which bounds actually failed to hold.
                             self.tcx.sess.struct_span_err(
                                 span,
-                                &format!("the type `{}` is not well-formed (chalk)", ty),
+                                &format!("the type `{}` is not well-formed", ty),
                             )
                         }
                     }
@@ -1215,6 +1225,25 @@ fn report_selection_error(
                 }
             }
 
+            OutputTypeParameterMismatch(
+                found_trait_ref,
+                expected_trait_ref,
+                terr @ TypeError::CyclicTy(_),
+            ) => {
+                let self_ty = found_trait_ref.self_ty().skip_binder();
+                let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
+                    (
+                        ObligationCause::dummy_with_span(tcx.def_span(def_id)),
+                        TypeError::CyclicTy(self_ty),
+                    )
+                } else {
+                    (obligation.cause.clone(), terr)
+                };
+                self.report_and_explain_type_error(
+                    TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+                    terr,
+                )
+            }
             OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
                 let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
                 let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
@@ -1387,7 +1416,6 @@ fn report_selection_error(
 
         self.note_obligation_cause(&mut err, &obligation);
         self.point_at_returns_when_relevant(&mut err, &obligation);
-
         err.emit();
     }
 }
@@ -2247,23 +2275,7 @@ fn maybe_report_ambiguity(
                 if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
                     (body_id, subst.map(|subst| subst.unpack()))
                 {
-                    struct FindExprBySpan<'hir> {
-                        span: Span,
-                        result: Option<&'hir hir::Expr<'hir>>,
-                    }
-
-                    impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> {
-                        fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-                            if self.span == ex.span {
-                                self.result = Some(ex);
-                            } else {
-                                hir::intravisit::walk_expr(self, ex);
-                            }
-                        }
-                    }
-
-                    let mut expr_finder = FindExprBySpan { span, result: None };
-
+                    let mut expr_finder = FindExprBySpan::new(span);
                     expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
 
                     if let Some(hir::Expr {
@@ -2750,6 +2762,36 @@ fn is_recursive_obligation(
     }
 }
 
+/// Crude way of getting back an `Expr` from a `Span`.
+pub struct FindExprBySpan<'hir> {
+    pub span: Span,
+    pub result: Option<&'hir hir::Expr<'hir>>,
+    pub ty_result: Option<&'hir hir::Ty<'hir>>,
+}
+
+impl<'hir> FindExprBySpan<'hir> {
+    fn new(span: Span) -> Self {
+        Self { span, result: None, ty_result: None }
+    }
+}
+
+impl<'v> Visitor<'v> for FindExprBySpan<'v> {
+    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+        if self.span == ex.span {
+            self.result = Some(ex);
+        } else {
+            hir::intravisit::walk_expr(self, ex);
+        }
+    }
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+        if self.span == ty.span {
+            self.ty_result = Some(ty);
+        } else {
+            hir::intravisit::walk_ty(self, ty);
+        }
+    }
+}
+
 /// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
 /// `param: ?Sized` would be a valid constraint.
 struct FindTypeParam {
@@ -2771,7 +2813,7 @@ fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
         // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
         // in that case should make what happened clear enough.
         match ty.kind {
-            hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
+            hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
             hir::TyKind::Path(hir::QPath::Resolved(None, path))
                 if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
             {
index 9bfe527647deea58886ce82ce839ab8f3f175fd3..b0a730c8ad16865d3b6f7c8a12dd688edf42ed85 100644 (file)
@@ -117,7 +117,7 @@ fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
                 Some(if movability.is_some() { "an async closure" } else { "a closure" })
             }),
             hir::Node::Expr(hir::Expr { .. }) => {
-                let parent_hid = hir.get_parent_node(hir_id);
+                let parent_hid = hir.parent_id(hir_id);
                 if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None }
             }
             _ => None,
index 472086eca8feb698bafb629b699d9c9b803984db..439854958270c4851385dd0d97d930a5edf559e4 100644 (file)
@@ -1,13 +1,16 @@
 // ignore-tidy-filelength
 
-use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
+use super::{
+    DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode,
+    PredicateObligation,
+};
 
 use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::{NormalizeExt, ObligationCtxt};
 
 use hir::def::CtorOf;
-use hir::HirId;
+use hir::{Expr, HirId};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
@@ -196,6 +199,20 @@ fn suggest_fn_call(
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool;
 
+    fn check_for_binding_assigned_block_without_tail_expression(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut Diagnostic,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
+    );
+
+    fn suggest_add_clone_to_arg(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut Diagnostic,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
+    ) -> bool;
+
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -248,7 +265,7 @@ fn suggest_impl_trait(
 
     fn point_at_returns_when_relevant(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
         obligation: &PredicateObligation<'tcx>,
     );
 
@@ -838,8 +855,7 @@ fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Op
 
         let hir = self.tcx.hir();
         let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?);
-        let parent_node = hir.get_parent_node(hir_id);
-        match hir.find(parent_node) {
+        match hir.find_parent(hir_id) {
             Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
                 get_name(err, &local.pat.kind)
             }
@@ -1033,6 +1049,115 @@ fn suggest_fn_call(
         true
     }
 
+    fn check_for_binding_assigned_block_without_tail_expression(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut Diagnostic,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
+    ) {
+        let mut span = obligation.cause.span;
+        while span.from_expansion() {
+            // Remove all the desugaring and macro contexts.
+            span.remove_mark();
+        }
+        let mut expr_finder = FindExprBySpan::new(span);
+        let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; };
+        expr_finder.visit_expr(&body);
+        let Some(expr) = expr_finder.result else { return; };
+        let Some(typeck) = &self.typeck_results else { return; };
+        let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; };
+        if !ty.is_unit() {
+            return;
+        };
+        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
+        let hir::def::Res::Local(hir_id) = path.res else { return; };
+        let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
+            return;
+        };
+        let Some(hir::Node::Local(hir::Local {
+            ty: None,
+            init: Some(init),
+            ..
+        })) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
+        let hir::ExprKind::Block(block, None) = init.kind else { return; };
+        if block.expr.is_some() {
+            return;
+        }
+        let [.., stmt] = block.stmts else {
+            err.span_label(block.span, "this empty block is missing a tail expression");
+            return;
+        };
+        let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
+        let Some(ty) = typeck.expr_ty_opt(tail_expr) else {
+            err.span_label(block.span, "this block is missing a tail expression");
+            return;
+        };
+        let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty));
+        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));
+
+        let new_obligation =
+            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
+        if self.predicate_must_hold_modulo_regions(&new_obligation) {
+            err.span_suggestion_short(
+                stmt.span.with_lo(tail_expr.span.hi()),
+                "remove this semicolon",
+                "",
+                Applicability::MachineApplicable,
+            );
+        } else {
+            err.span_label(block.span, "this block is missing a tail expression");
+        }
+    }
+
+    fn suggest_add_clone_to_arg(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut Diagnostic,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
+    ) -> bool {
+        let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
+        let ty = self.tcx.erase_late_bound_regions(self_ty);
+        let owner = self.tcx.hir().get_parent_item(obligation.cause.body_id);
+        let Some(generics) = self.tcx.hir().get_generics(owner.def_id) else { return false };
+        let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
+        let ty::Param(param) = inner_ty.kind() else { return false };
+        let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false };
+        let arg_node = self.tcx.hir().get(*arg_hir_id);
+        let Node::Expr(Expr { kind: hir::ExprKind::Path(_), ..}) = arg_node else { return false };
+
+        let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
+        let has_clone = |ty| {
+            self.type_implements_trait(clone_trait, [ty], obligation.param_env)
+                .must_apply_modulo_regions()
+        };
+
+        let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+            obligation.param_env,
+            trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
+        );
+
+        if self.predicate_may_hold(&new_obligation) && has_clone(ty) {
+            if !has_clone(param.to_ty(self.tcx)) {
+                suggest_constraining_type_param(
+                    self.tcx,
+                    generics,
+                    err,
+                    param.name.as_str(),
+                    "Clone",
+                    Some(clone_trait),
+                );
+            }
+            err.span_suggestion_verbose(
+                obligation.cause.span.shrink_to_hi(),
+                "consider using clone here",
+                ".clone()".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+            return true;
+        }
+        false
+    }
+
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -1394,6 +1519,13 @@ fn suggest_change_mut(
                         .source_map()
                         .span_take_while(span, |c| c.is_whitespace() || *c == '&');
                     if points_at_arg && mutability.is_not() && refs_number > 0 {
+                        // If we have a call like foo(&mut buf), then don't suggest foo(&mut mut buf)
+                        if snippet
+                            .trim_start_matches(|c: char| c.is_whitespace() || c == '&')
+                            .starts_with("mut")
+                        {
+                            return;
+                        }
                         err.span_suggestion_verbose(
                             sp,
                             "consider changing this borrow's mutability",
@@ -1421,7 +1553,7 @@ fn suggest_semicolon_removal(
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         let hir = self.tcx.hir();
-        let parent_node = hir.get_parent_node(obligation.cause.body_id);
+        let parent_node = hir.parent_id(obligation.cause.body_id);
         let node = hir.find(parent_node);
         if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
             && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
@@ -1458,7 +1590,7 @@ fn suggest_semicolon_removal(
 
     fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
         let hir = self.tcx.hir();
-        let parent_node = hir.get_parent_node(obligation.cause.body_id);
+        let parent_node = hir.parent_id(obligation.cause.body_id);
         let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else {
             return None;
         };
@@ -1483,7 +1615,7 @@ fn suggest_impl_trait(
         }
 
         let hir = self.tcx.hir();
-        let fn_hir_id = hir.get_parent_node(obligation.cause.body_id);
+        let fn_hir_id = hir.parent_id(obligation.cause.body_id);
         let node = hir.find(fn_hir_id);
         let Some(hir::Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(sig, _, body_id),
@@ -1686,7 +1818,7 @@ fn suggest_impl_trait(
 
     fn point_at_returns_when_relevant(
         &self,
-        err: &mut Diagnostic,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
         obligation: &PredicateObligation<'tcx>,
     ) {
         match obligation.cause.code().peel_derives() {
@@ -1695,7 +1827,7 @@ fn point_at_returns_when_relevant(
         }
 
         let hir = self.tcx.hir();
-        let parent_node = hir.get_parent_node(obligation.cause.body_id);
+        let parent_node = hir.parent_id(obligation.cause.body_id);
         let node = hir.find(parent_node);
         if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
             node
@@ -1708,7 +1840,15 @@ fn point_at_returns_when_relevant(
             for expr in &visitor.returns {
                 if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
                     let ty = self.resolve_vars_if_possible(returned_ty);
-                    err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
+                    if ty.references_error() {
+                        // don't print out the [type error] here
+                        err.delay_as_bug();
+                    } else {
+                        err.span_label(
+                            expr.span,
+                            &format!("this returned value is of type `{}`", ty),
+                        );
+                    }
                 }
             }
         }
@@ -2291,7 +2431,7 @@ fn note_obligation_cause_for_async_await(
                         let expr = hir.expect_expr(expr_id);
                         debug!("target_ty evaluated from {:?}", expr);
 
-                        let parent = hir.get_parent_node(expr_id);
+                        let parent = hir.parent_id(expr_id);
                         if let Some(hir::Node::Expr(e)) = hir.find(parent) {
                             let parent_span = hir.span(parent);
                             let parent_did = parent.owner.to_def_id();
@@ -2512,8 +2652,17 @@ fn note_obligation_cause_code<T>(
                 }
             }
             ObligationCauseCode::VariableType(hir_id) => {
-                let parent_node = self.tcx.hir().get_parent_node(hir_id);
+                let parent_node = self.tcx.hir().parent_id(hir_id);
                 match self.tcx.hir().find(parent_node) {
+                    Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
+                        err.span_suggestion_verbose(
+                            ty.span.shrink_to_lo(),
+                            "consider borrowing here",
+                            "&",
+                            Applicability::MachineApplicable,
+                        );
+                        err.note("all local variables must have a statically known size");
+                    }
                     Some(Node::Local(hir::Local {
                         init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
                         ..
@@ -2683,7 +2832,9 @@ fn note_obligation_cause_code<T>(
                 // Don't print the tuple of capture types
                 'print: {
                     if !is_upvar_tys_infer_tuple {
-                        let msg = format!("required because it appears within the type `{}`", ty);
+                        let msg = with_forced_trimmed_paths!(format!(
+                            "required because it appears within the type `{ty}`",
+                        ));
                         match ty.kind() {
                             ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
                                 Some(ident) => err.span_note(ident.span, &msg),
@@ -2724,7 +2875,7 @@ fn note_obligation_cause_code<T>(
                                 let mut msg =
                                     "required because it captures the following types: ".to_owned();
                                 for ty in bound_tys.skip_binder() {
-                                    write!(msg, "`{}`, ", ty).unwrap();
+                                    with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap());
                                 }
                                 err.note(msg.trim_end_matches(", "))
                             }
@@ -2735,7 +2886,9 @@ fn note_obligation_cause_code<T>(
                                 let kind = tcx.generator_kind(def_id).unwrap().descr();
                                 err.span_note(
                                     sp,
-                                    &format!("required because it's used within this {}", kind),
+                                    with_forced_trimmed_paths!(&format!(
+                                        "required because it's used within this {kind}",
+                                    )),
                                 )
                             }
                             ty::Closure(def_id, _) => err.span_note(
@@ -2959,7 +3112,9 @@ fn note_obligation_cause_code<T>(
                     let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty));
                     err.span_label(
                         expr_span,
-                        format!("return type was inferred to be `{expr_ty}` here"),
+                        with_forced_trimmed_paths!(format!(
+                            "return type was inferred to be `{expr_ty}` here",
+                        )),
                     );
                 }
             }
@@ -2977,7 +3132,7 @@ fn suggest_await_before_try(
         span: Span,
     ) {
         let body_hir_id = obligation.cause.body_id;
-        let item_id = self.tcx.hir().get_parent_node(body_hir_id);
+        let item_id = self.tcx.hir().parent_id(body_hir_id);
 
         if let Some(body_id) =
             self.tcx.hir().maybe_body_owned_by(self.tcx.hir().local_def_id(item_id))
@@ -3204,7 +3359,7 @@ fn note_function_argument_obligation(
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
                 && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
-                && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
+                && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id)
                 && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
                 && let Some(binding_expr) = local.init
             {
@@ -3222,7 +3377,7 @@ fn note_function_argument_obligation(
         })) = call_node
         {
             if Some(rcvr.span) == err.span.primary_span() {
-                err.replace_span_with(path.ident.span);
+                err.replace_span_with(path.ident.span, true);
             }
         }
         if let Some(Node::Expr(hir::Expr {
@@ -3272,8 +3427,7 @@ fn point_at_chain(
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
                 && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
-                && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
-                && let Some(parent) = self.tcx.hir().find(parent_hir_id)
+                && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
             {
                 // We've reached the root of the method call chain...
                 if let hir::Node::Local(local) = parent
index c30531fa906642c090bd7abb9e2389a64773d38e..2bab380dba011e4041e1212fc4fbb2142b795857 100644 (file)
@@ -102,7 +102,7 @@ pub enum TraitQueryMode {
     /// spans etc. passed in and hence can do reasonable
     /// error reporting on their own.
     Standard,
-    /// Canonicalized queries get dummy spans and hence
+    /// Canonical queries get dummy spans and hence
     /// must generally propagate errors to
     /// pre-canonicalization callsites.
     Canonical,
index 5276da2e49c750743c4b9d26a2909eb843926de8..f7614997585cf910c1173db7d58b9e610e11af59 100644 (file)
@@ -2284,7 +2284,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         obligation.param_env,
         cause.clone(),
         obligation.recursion_depth + 1,
-        tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
+        tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id)
             .map_bound(|tys| {
                 tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id])
             })
index 86b015767f0f85cf7533cb656b30ccd4169d05d8..e6db96c9e558044826e31fb7d40322fce56d6ed2 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
@@ -16,8 +16,8 @@ fn try_fast_path(
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
         tcx.type_op_ascribe_user_type(canonicalized)
     }
 }
index 490114aacd1355ff65cf8cff3ce207d8ab1c3c60..8c9b9610cb6efe6cda5bb4c92a07defc094b8310 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
@@ -16,8 +16,8 @@ fn try_fast_path(
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
         tcx.type_op_eq(canonicalized)
     }
 }
index 2a3319f0f26fbc15d29da71fe9c07d7f5f5fcf78..18d7c9b193601c161b258fa926e1c1a30763aba7 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
@@ -27,8 +27,8 @@ fn try_fast_path(
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
         // FIXME this `unchecked_map` is only necessary because the
         // query is defined as taking a `ParamEnvAnd<Ty>`; it should
         // take an `ImpliedOutlivesBounds` instead
index 29ae8ae6b6e555edee8244eb73091a0240c415d1..97002b461aa9be0e295584b5e8737ec95f7d1863 100644 (file)
@@ -1,10 +1,10 @@
 use crate::infer::canonical::{
-    Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints,
+    Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
 };
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::query::Fallible;
 use crate::traits::ObligationCause;
-use rustc_infer::infer::canonical::{Canonical, Certainty};
+use rustc_infer::infer::canonical::Certainty;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -73,8 +73,8 @@ fn try_fast_path(
     /// not captured in the return value.
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>;
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>>;
 
     fn fully_perform_into(
         query_key: ParamEnvAnd<'tcx, Self>,
index e92ca7325d3490a054dc6943918d7f9ebc4babc0..8f0b4de31e6cf147fcad26eb51bcdc69b1850428 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
@@ -18,8 +18,8 @@ fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T>
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
         T::type_op_method(tcx, canonicalized)
     }
 }
@@ -27,15 +27,15 @@ fn perform_query(
 pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>;
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>>;
 }
 
 impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_ty(canonicalized)
     }
 }
@@ -43,8 +43,8 @@ fn type_op_method(
 impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_predicate(canonicalized)
     }
 }
@@ -52,8 +52,8 @@ fn type_op_method(
 impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_poly_fn_sig(canonicalized)
     }
 }
@@ -61,8 +61,8 @@ fn type_op_method(
 impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
 }
index b63382429d0aa394baa4e4cee2464f781274e2b0..0d42cd8250a19ec0e812207fa502139a4caffa5c 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult};
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
@@ -30,8 +30,8 @@ fn try_fast_path(
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
         // Subtle: note that we are not invoking
         // `infcx.at(...).dropck_outlives(...)` here, but rather the
         // underlying `dropck_outlives` query. This same underlying
index 68434c2b68d7b8b53c32934c63b4cdfab584ce25..b63da28e27475a046b067fe40e72e25459688b6c 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
 
@@ -32,8 +32,8 @@ fn try_fast_path(
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+        mut canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
         match canonicalized.value.value.predicate.kind().skip_binder() {
             ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
                 canonicalized.value.param_env.remap_constness_with(pred.constness);
index 57290b6691410baab19fd8d2f9883d56651efea2..c51292eba14be183851ca6d819fa36f81300b861 100644 (file)
@@ -1,4 +1,4 @@
-use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 
@@ -13,8 +13,8 @@ fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()
 
     fn perform_query(
         tcx: TyCtxt<'tcx>,
-        canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
         tcx.type_op_subtype(canonicalized)
     }
 }
index f6fe71fbd4f889ce18c08f0c08b890b4939363c1..15526b34ed2d851a6f357b67e220e281b23cf52d 100644 (file)
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::{
-    self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
-    ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
+    self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
+    ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt,
 };
+use rustc_session::config::TraitSolver;
 use rustc_span::def_id::DefId;
 
 use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@@ -98,8 +99,8 @@ pub(super) fn confirm_candidate(
                 ImplSource::Future(vtable_future)
             }
 
-            FnPointerCandidate { .. } => {
-                let data = self.confirm_fn_pointer_candidate(obligation)?;
+            FnPointerCandidate { is_const } => {
+                let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
                 ImplSource::FnPointer(data)
             }
 
@@ -597,17 +598,19 @@ fn confirm_object_candidate(
     fn confirm_fn_pointer_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
+        is_const: bool,
     ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
     {
         debug!(?obligation, "confirm_fn_pointer_candidate");
 
+        let tcx = self.tcx();
         let self_ty = self
             .infcx
             .shallow_resolve(obligation.self_ty().no_bound_vars())
             .expect("fn pointer should not capture bound vars from predicate");
-        let sig = self_ty.fn_sig(self.tcx());
+        let sig = self_ty.fn_sig(tcx);
         let trait_ref = closure_trait_ref_and_return_type(
-            self.tcx(),
+            tcx,
             obligation.predicate.def_id(),
             self_ty,
             sig,
@@ -616,9 +619,19 @@ fn confirm_fn_pointer_candidate(
         .map_bound(|(trait_ref, _)| trait_ref);
 
         let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+        if obligation.is_const() && !is_const {
+            // function is a trait method
+            if let ty::FnDef(def_id, substs) = self_ty.kind() && let Some(trait_id) = tcx.trait_of_item(*def_id) {
+                let trait_ref = TraitRef::from_method(tcx, trait_id, *substs);
+                let poly_trait_pred = Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst);
+                let obligation = Obligation::new(tcx, cause.clone(), obligation.param_env, poly_trait_pred);
+                nested.push(obligation);
+            }
+        }
 
         // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
-        let cause = obligation.derived_cause(BuiltinDerivedObligation);
         let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
         let output_ty = normalize_with_depth_to(
             self,
@@ -755,8 +768,7 @@ fn confirm_closure_candidate(
         debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
 
         // FIXME: Chalk
-
-        if !self.tcx().sess.opts.unstable_opts.chalk {
+        if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Chalk {
             nested.push(obligation.with(
                 self.tcx(),
                 ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)),
index 81e8f9e914c2373ceae19be1daf898dc54e1a2d8..3f14491f8032ffa069742c9b506c72feb58e3891 100644 (file)
@@ -755,7 +755,7 @@ fn evaluate_predicate_recursively<'o>(
                     // contain the "'static" lifetime (any other lifetime
                     // would either be late-bound or local), so it is guaranteed
                     // to outlive any other lifetime
-                    if pred.0.is_global() && !pred.0.has_late_bound_regions() {
+                    if pred.0.is_global() && !pred.0.has_late_bound_vars() {
                         Ok(EvaluatedToOk)
                     } else {
                         Ok(EvaluatedToOkModuloRegions)
@@ -1374,6 +1374,14 @@ fn filter_impls(
                     FutureCandidate => {}
                     // FnDef where the function is const
                     FnPointerCandidate { is_const: true } => {}
+                    FnPointerCandidate { is_const: false } => {
+                        if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() {
+                            // Trait methods are not seen as const unless the trait is implemented as const.
+                            // We do not filter that out in here, but nested obligations will be needed to confirm this.
+                        } else {
+                            continue
+                        }
+                    }
                     ConstDestructCandidate(_) => {}
                     _ => {
                         // reject all other types of candidates
@@ -1777,9 +1785,8 @@ fn candidate_should_be_dropped_in_favor_of(
         // Check if a bound would previously have been removed when normalizing
         // the param_env so that it can be given the lowest priority. See
         // #50825 for the motivation for this.
-        let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
-            cand.is_global() && !cand.has_late_bound_regions()
-        };
+        let is_global =
+            |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_late_bound_vars();
 
         // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
         // `DiscriminantKindCandidate`, `ConstDestructCandidate`
index f3ca6a6c779a06b9ca34b584dde18fe5775f0516..b5df583e3f4cbb94d5fb2e38aa1b7cab2ffd1d0a 100644 (file)
@@ -1,6 +1,5 @@
 use rustc_errors::Diagnostic;
 use rustc_span::Span;
-use smallvec::smallvec;
 use smallvec::SmallVec;
 
 use rustc_data_structures::fx::FxHashSet;
index 3f661ce69235caaf0cb69c8df90277e9fdbfb0be..481b56e111ea0a6d74099f0017f166fa7e5afad2 100644 (file)
@@ -189,7 +189,7 @@ fn dtorck_constraint_for_ty<'tcx>(
 
                 tcx.sess.delay_span_bug(
                     span,
-                    &format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,),
+                    &format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
                 );
                 return Err(NoSolution);
             }
@@ -231,7 +231,7 @@ fn dtorck_constraint_for_ty<'tcx>(
                 // be fully resolved.
                 tcx.sess.delay_span_bug(
                     span,
-                    &format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,),
+                    &format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
                 );
                 return Err(NoSolution);
             }
index 6e6bc62a040d11df006d5d30727948c9253e9c19..5cad2c2ccb0f7f562f2ebd5efd43c3767736ee79 100644 (file)
@@ -47,7 +47,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq +
             // us a test case.
             debug_assert_eq!(normalized_value, resolved_value);
             let erased = infcx.tcx.erase_regions(resolved_value);
-            debug_assert!(!erased.needs_infer(), "{:?}", erased);
+            debug_assert!(!erased.needs_infer(), "{erased:?}");
             Ok(erased)
         }
         Err(NoSolution) => Err(NoSolution),
index 7f964afde80fd1d4b90f925796562b86b0c2ff94..aa5c83ac2e6557cd98e40f7d29cbc18db5a99853 100644 (file)
@@ -4,8 +4,8 @@
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate};
-use rustc_middle::ty::{UserSelfTy, UserSubsts};
+use rustc_middle::ty::{ParamEnvAnd, Predicate};
+use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
@@ -50,13 +50,46 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
     key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
     span: Option<Span>,
 ) -> Result<(), NoSolution> {
-    let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
-    debug!(
-        "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
-        mir_ty, def_id, user_substs
-    );
+    let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
+    debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
     let span = span.unwrap_or(DUMMY_SP);
+    match user_ty {
+        UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
+        UserType::TypeOf(def_id, user_substs) => {
+            relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
+        }
+    };
+    Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_ty<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    span: Span,
+    mir_ty: Ty<'tcx>,
+    user_ty: Ty<'tcx>,
+) -> Result<(), NoSolution> {
+    let cause = ObligationCause::dummy_with_span(span);
+    let user_ty = ocx.normalize(&cause, param_env, user_ty);
+    ocx.eq(&cause, param_env, mir_ty, user_ty)?;
 
+    // FIXME(#104764): We should check well-formedness before normalization.
+    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
+    ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
+
+    Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_substs<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    span: Span,
+    mir_ty: Ty<'tcx>,
+    def_id: hir::def_id::DefId,
+    user_substs: UserSubsts<'tcx>,
+) -> Result<(), NoSolution> {
     let UserSubsts { user_self_ty, substs } = user_substs;
     let tcx = ocx.infcx.tcx;
     let cause = ObligationCause::dummy_with_span(span);
@@ -91,13 +124,13 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
     }
 
     if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+        let self_ty = ocx.normalize(&cause, param_env, self_ty);
         let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs);
         let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
 
         ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
 
-        let predicate: Predicate<'tcx> =
-            ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())).to_predicate(tcx);
+        let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
         ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
     }
 
@@ -112,8 +145,7 @@ pub fn type_op_ascribe_user_type_with_span<'tcx>(
     // them?  This would only be relevant if some input
     // type were ill-formed but did not appear in `ty`,
     // which...could happen with normalization...
-    let predicate: Predicate<'tcx> =
-        ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx);
+    let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
     ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
     Ok(())
 }
index 07035ebdfb167953d5d3d8ef1c0dbf57d6b9e035..f8d05bc89d26d1f96f826c1e3d3b838392e422e0 100644 (file)
@@ -24,7 +24,7 @@ impl fmt::Debug for Byte {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match &self {
             Self::Uninit => f.write_str("??u8"),
-            Self::Init(b) => write!(f, "{:#04x}u8", b),
+            Self::Init(b) => write!(f, "{b:#04x}u8"),
         }
     }
 }
index d644cbccea11b2df6c5080a2191ad3c1c8b8f4f1..f8a5691f29de0b0626d207779af0c2ccd997ee47 100644 (file)
@@ -256,6 +256,11 @@ fn adjust_for_rust_scalar<'tcx>(
             // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
             let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true);
 
+            // LLVM prior to version 12 had known miscompiles in the presence of noalias attributes
+            // (see #54878), so it was conditionally disabled, but we don't support earlier
+            // 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.unwrap_or(true);
+
             // `&mut` pointer parameters never alias other parameters,
             // or mutable global data
             //
@@ -263,29 +268,21 @@ fn adjust_for_rust_scalar<'tcx>(
             // 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
-            //
-            // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
-            // for UniqueBorrowed arguments, so that the codegen backend can decide whether
-            // or not to actually emit the attribute. It can also be controlled with the
-            // `-Zmutable-noalias` debugging option.
             let no_alias = match kind {
-                PointerKind::SharedMutable
-                | PointerKind::UniqueBorrowed
-                | PointerKind::UniqueBorrowedPinned => false,
+                PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false,
+                PointerKind::UniqueBorrowed => noalias_mut_ref,
                 PointerKind::UniqueOwned => noalias_for_box,
-                PointerKind::Frozen => !is_return,
+                PointerKind::Frozen => true,
             };
-            if no_alias {
+            // 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>).
+            if no_alias && !is_return {
                 attrs.set(ArgAttribute::NoAlias);
             }
 
             if kind == PointerKind::Frozen && !is_return {
                 attrs.set(ArgAttribute::ReadOnly);
             }
-
-            if kind == PointerKind::UniqueBorrowed && !is_return {
-                attrs.set(ArgAttribute::NoAliasMutRef);
-            }
         }
     }
 }
index 2da98d3342984bb7231514d46caeec899e442075..8d46ba320fc031d56044b43e3a4225e711c02bfc 100644 (file)
@@ -194,7 +194,7 @@ fn resolve_associated_item<'tcx>(
                 && trait_item_id != leaf_def.item.def_id
                 && let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
             {
-                tcx.compare_assoc_const_impl_item_with_trait_item((
+                tcx.compare_impl_const((
                     leaf_def_item,
                     trait_item_id,
                 ))?;
index c8c6acaa45397771641b180415290fe3bb4c2edb..6aa016133ca598926fffa1b2823962b11332da92 100644 (file)
@@ -155,17 +155,37 @@ fn layout_of_uncached<'tcx>(
             }
 
             let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
-            let metadata = match unsized_part.kind() {
-                ty::Foreign(..) => {
+
+            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
+                let metadata_ty = tcx.normalize_erasing_regions(
+                    param_env,
+                    tcx.mk_projection(metadata_def_id, [pointee]),
+                );
+                let metadata_layout = cx.layout_of(metadata_ty)?;
+                // If the metadata is a 1-zst, then the pointer is thin.
+                if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 {
                     return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
                 }
-                ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
-                ty::Dynamic(..) => {
-                    let mut vtable = scalar_unit(Pointer);
-                    vtable.valid_range_mut().start = 1;
-                    vtable
+
+                let Abi::Scalar(metadata) = metadata_layout.abi else {
+                    return Err(LayoutError::Unknown(unsized_part));
+                };
+                metadata
+            } else {
+                match unsized_part.kind() {
+                    ty::Foreign(..) => {
+                        return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+                    }
+                    ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
+                    ty::Dynamic(..) => {
+                        let mut vtable = scalar_unit(Pointer);
+                        vtable.valid_range_mut().start = 1;
+                        vtable
+                    }
+                    _ => {
+                        return Err(LayoutError::Unknown(unsized_part));
+                    }
                 }
-                _ => return Err(LayoutError::Unknown(unsized_part)),
             };
 
             // Effectively a (ptr, meta) tuple.
index e2d10f550c326d9151265196c0c11bc5c9ff5fb6..87923ebbe4bc948502d1fefca6a13935867bf864 100644 (file)
@@ -2,6 +2,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
+use rustc_session::config::TraitSolver;
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -121,7 +122,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // are any errors at that point, so outside of type inference you can be
     // sure that this will succeed without errors anyway.
 
-    if tcx.sess.opts.unstable_opts.chalk {
+    if tcx.sess.opts.unstable_opts.trait_solver == TraitSolver::Chalk {
         let environment = well_formed_types_in_env(tcx, def_id);
         predicates.extend(environment);
     }
@@ -161,7 +162,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
                 kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
                 ..
             }) => {
-                let parent_hir_id = tcx.hir().get_parent_node(hir_id);
+                let parent_hir_id = tcx.hir().parent_id(hir_id);
                 match tcx.hir().get(parent_hir_id) {
                     hir::Node::Item(hir::Item {
                         kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
index dd36a5c7a2169af3af0ed9e267b46d5e0cfabd0b..44004cb0be1e9dbf9ae4c4e6b850a0fe677d894a 100644 (file)
@@ -241,22 +241,30 @@ pub struct TypeFlags: u32 {
         /// Basically anything but `ReLateBound` and `ReErased`.
         const HAS_FREE_REGIONS            = 1 << 14;
 
-        /// Does this have any `ReLateBound` regions? Used to check
-        /// if a global bound is safe to evaluate.
+        /// Does this have any `ReLateBound` regions?
         const HAS_RE_LATE_BOUND           = 1 << 15;
+        /// Does this have any `Bound` types?
+        const HAS_TY_LATE_BOUND           = 1 << 16;
+        /// Does this have any `ConstKind::Bound` consts?
+        const HAS_CT_LATE_BOUND           = 1 << 17;
+        /// Does this have any bound variables?
+        /// Used to check if a global bound is safe to evaluate.
+        const HAS_LATE_BOUND              = TypeFlags::HAS_RE_LATE_BOUND.bits
+                                          | TypeFlags::HAS_TY_LATE_BOUND.bits
+                                          | TypeFlags::HAS_CT_LATE_BOUND.bits;
 
         /// Does this have any `ReErased` regions?
-        const HAS_RE_ERASED               = 1 << 16;
+        const HAS_RE_ERASED               = 1 << 18;
 
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
-        const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+        const STILL_FURTHER_SPECIALIZABLE = 1 << 19;
 
         /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
-        const HAS_TY_FRESH                = 1 << 18;
+        const HAS_TY_FRESH                = 1 << 20;
 
         /// Does this value have `InferConst::Fresh`?
-        const HAS_CT_FRESH                = 1 << 19;
+        const HAS_CT_FRESH                = 1 << 21;
     }
 }
 
@@ -718,9 +726,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             TyVar(ref v) => v.fmt(f),
             IntVar(ref v) => v.fmt(f),
             FloatVar(ref v) => v.fmt(f),
-            FreshTy(v) => write!(f, "FreshTy({:?})", v),
-            FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
-            FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
+            FreshTy(v) => write!(f, "FreshTy({v:?})"),
+            FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"),
+            FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"),
         }
     }
 }
@@ -743,9 +751,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             TyVar(_) => write!(f, "_"),
             IntVar(_) => write!(f, "{}", "{integer}"),
             FloatVar(_) => write!(f, "{}", "{float}"),
-            FreshTy(v) => write!(f, "FreshTy({})", v),
-            FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
-            FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v),
+            FreshTy(v) => write!(f, "FreshTy({v})"),
+            FreshIntTy(v) => write!(f, "FreshIntTy({v})"),
+            FreshFloatTy(v) => write!(f, "FreshFloatTy({v})"),
         }
     }
 }
index f30ae82d7cdd2b4fd4d596c0e207f016efa4aada..b944cbd698d13598de404d3f6291718cb7259dfe 100644 (file)
@@ -1028,10 +1028,10 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) -> () {
 impl<I: Interner> fmt::Debug for RegionKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            ReEarlyBound(data) => write!(f, "ReEarlyBound({:?})", data),
+            ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"),
 
             ReLateBound(binder_id, bound_region) => {
-                write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
+                write!(f, "ReLateBound({binder_id:?}, {bound_region:?})")
             }
 
             ReFree(fr) => fr.fmt(f),
@@ -1040,7 +1040,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
             ReVar(vid) => vid.fmt(f),
 
-            RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
+            RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
 
             ReErased => f.write_str("ReErased"),
         }
index 265020209eb12742c64b4c8c48a98856bc55ed7b..95c07abf73106647bc3a6c3f3909caff11cce0ed 100644 (file)
@@ -13,8 +13,8 @@ core = { path = "../core" }
 compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
 
 [dev-dependencies]
-rand = "0.7"
-rand_xorshift = "0.2"
+rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+rand_xorshift = "0.3.0"
 
 [[test]]
 name = "collectionstests"
index bd6f38f2f100322d57fe9569bd8fe01b66ff9258..b62be9d39a1cd393a330deb7f3df688f6137d120 100644 (file)
@@ -1,6 +1,6 @@
 use std::{mem, ptr};
 
-use rand::distributions::{Alphanumeric, Standard};
+use rand::distributions::{Alphanumeric, DistString, Standard};
 use rand::Rng;
 use test::{black_box, Bencher};
 
@@ -218,7 +218,7 @@ fn gen_strings(len: usize) -> Vec<String> {
     let mut v = vec![];
     for _ in 0..len {
         let n = rng.gen::<usize>() % 20 + 1;
-        v.push((&mut rng).sample_iter(&Alphanumeric).take(n).collect());
+        v.push(Alphanumeric.sample_string(&mut rng, n));
     }
     v
 }
index e5fbfc55761f41302171b33cf17ac00acc1602bc..fe6de1cf879b2e2395173f1d4e5d3c80ea2a1fe9 100644 (file)
@@ -23,7 +23,7 @@
     // These are the magic symbols to call the global allocator.  rustc generates
     // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
     // (the code expanding that attribute macro generates those functions), or to call
-    // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
+    // the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
     // otherwise.
     // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
     // like `malloc`, `realloc`, and `free`, respectively.
@@ -402,20 +402,20 @@ pub mod __alloc_error_handler {
     // `#[alloc_error_handler]`.
     #[rustc_std_internal_symbol]
     pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
-        panic!("memory allocation of {size} bytes failed")
-    }
-
-    #[cfg(bootstrap)]
-    #[rustc_std_internal_symbol]
-    pub unsafe fn __rg_oom(size: usize, align: usize) -> ! {
-        use crate::alloc::Layout;
-
-        let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
         extern "Rust" {
-            #[lang = "oom"]
-            fn oom_impl(layout: Layout) -> !;
+            // This symbol is emitted by rustc next to __rust_alloc_error_handler.
+            // Its value depends on the -Zoom={panic,abort} compiler option.
+            static __rust_alloc_error_handler_should_panic: u8;
+        }
+
+        #[allow(unused_unsafe)]
+        if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+            panic!("memory allocation of {size} bytes failed")
+        } else {
+            core::panicking::panic_nounwind_fmt(format_args!(
+                "memory allocation of {size} bytes failed"
+            ))
         }
-        unsafe { oom_impl(layout) }
     }
 }
 
index b154688fb087b94626f87e0a1f7af57d3f507ebb..a563b2587236c57abdec2689aac5f1e1127cbde4 100644 (file)
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
 use core::iter::{FusedIterator, Iterator};
-#[cfg(not(bootstrap))]
 use core::marker::Tuple;
 use core::marker::{Destruct, Unpin, Unsize};
 use core::mem;
@@ -954,7 +953,7 @@ impl<T: ?Sized> Box<T> {
     /// [`Layout`]: crate::Layout
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
-    #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"]
+    #[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
     pub unsafe fn from_raw(raw: *mut T) -> Self {
         unsafe { Self::from_raw_in(raw, Global) }
     }
@@ -1981,17 +1980,6 @@ fn is_empty(&self) -> bool {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
 
-#[cfg(bootstrap)]
-#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
-impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
-    type Output = <F as FnOnce<Args>>::Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
-        <F as FnOnce<Args>>::call_once(*self, args)
-    }
-}
-
-#[cfg(not(bootstrap))]
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
     type Output = <F as FnOnce<Args>>::Output;
@@ -2001,15 +1989,6 @@ extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
     }
 }
 
-#[cfg(bootstrap)]
-#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
-impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
-        <F as FnMut<Args>>::call_mut(self, args)
-    }
-}
-
-#[cfg(not(bootstrap))]
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args: Tuple, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
@@ -2017,15 +1996,6 @@ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
     }
 }
 
-#[cfg(bootstrap)]
-#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
-impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
-    extern "rust-call" fn call(&self, args: Args) -> Self::Output {
-        <F as Fn<Args>>::call(self, args)
-    }
-}
-
-#[cfg(not(bootstrap))]
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
     extern "rust-call" fn call(&self, args: Args) -> Self::Output {
index c477c44906c97abce7164af4da82caf1a19ef295..c1a82e452f6c361d9c1d2cd900fd85bb2e5cb697 100644 (file)
@@ -226,24 +226,45 @@ fn new<T>(header: H, value: T) -> WithHeader<H> {
     // - Assumes that either `value` can be dereferenced, or is the
     //   `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
     unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
+        struct DropGuard<H> {
+            ptr: NonNull<u8>,
+            value_layout: Layout,
+            _marker: PhantomData<H>,
+        }
+
+        impl<H> Drop for DropGuard<H> {
+            fn drop(&mut self) {
+                unsafe {
+                    // SAFETY: Layout must have been computable if we're in drop
+                    let (layout, value_offset) =
+                        WithHeader::<H>::alloc_layout(self.value_layout).unwrap_unchecked();
+
+                    // Note: Don't deallocate if the layout size is zero, because the pointer
+                    // didn't come from the allocator.
+                    if layout.size() != 0 {
+                        alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout);
+                    } else {
+                        debug_assert!(
+                            value_offset == 0
+                                && mem::size_of::<H>() == 0
+                                && self.value_layout.size() == 0
+                        );
+                    }
+                }
+            }
+        }
+
         unsafe {
-            let value_layout = Layout::for_value_raw(value);
-            // SAFETY: Layout must have been computable if we're in drop
-            let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked();
+            // `_guard` will deallocate the memory when dropped, even if `drop_in_place` unwinds.
+            let _guard = DropGuard {
+                ptr: self.0,
+                value_layout: Layout::for_value_raw(value),
+                _marker: PhantomData::<H>,
+            };
 
             // We only drop the value because the Pointee trait requires that the metadata is copy
             // aka trivially droppable.
             ptr::drop_in_place::<T>(value);
-
-            // Note: Don't deallocate if the layout size is zero, because the pointer
-            // didn't come from the allocator.
-            if layout.size() != 0 {
-                alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
-            } else {
-                debug_assert!(
-                    value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
-                );
-            }
         }
     }
 
index 5a05215aeeddfcd6b0e2f34c4c95f5a9b3b0714c..59c516374c0e2790d6c2357b6ed1566afa7c2344 100644 (file)
@@ -1,8 +1,8 @@
 use super::*;
 use crate::boxed::Box;
+use crate::testing::crash_test::{CrashTestDummy, Panic};
 use std::iter::TrustedLen;
 use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::sync::atomic::{AtomicU32, Ordering};
 
 #[test]
 fn test_iterator() {
@@ -291,33 +291,83 @@ fn test_drain_sorted() {
 
 #[test]
 fn test_drain_sorted_leak() {
-    static DROPS: AtomicU32 = AtomicU32::new(0);
-
-    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
-    struct D(u32, bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            DROPS.fetch_add(1, Ordering::SeqCst);
-
-            if self.1 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
+    let d0 = CrashTestDummy::new(0);
+    let d1 = CrashTestDummy::new(1);
+    let d2 = CrashTestDummy::new(2);
+    let d3 = CrashTestDummy::new(3);
+    let d4 = CrashTestDummy::new(4);
+    let d5 = CrashTestDummy::new(5);
     let mut q = BinaryHeap::from(vec![
-        D(0, false),
-        D(1, false),
-        D(2, false),
-        D(3, true),
-        D(4, false),
-        D(5, false),
+        d0.spawn(Panic::Never),
+        d1.spawn(Panic::Never),
+        d2.spawn(Panic::Never),
+        d3.spawn(Panic::InDrop),
+        d4.spawn(Panic::Never),
+        d5.spawn(Panic::Never),
     ]);
 
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
+    catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).unwrap_err();
+
+    assert_eq!(d0.dropped(), 1);
+    assert_eq!(d1.dropped(), 1);
+    assert_eq!(d2.dropped(), 1);
+    assert_eq!(d3.dropped(), 1);
+    assert_eq!(d4.dropped(), 1);
+    assert_eq!(d5.dropped(), 1);
+    assert!(q.is_empty());
+}
 
-    assert_eq!(DROPS.load(Ordering::SeqCst), 6);
+#[test]
+fn test_drain_forget() {
+    let a = CrashTestDummy::new(0);
+    let b = CrashTestDummy::new(1);
+    let c = CrashTestDummy::new(2);
+    let mut q =
+        BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]);
+
+    catch_unwind(AssertUnwindSafe(|| {
+        let mut it = q.drain();
+        it.next();
+        mem::forget(it);
+    }))
+    .unwrap();
+    // Behaviour after leaking is explicitly unspecified and order is arbitrary,
+    // so it's fine if these start failing, but probably worth knowing.
+    assert!(q.is_empty());
+    assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1);
+    assert_eq!(a.dropped(), 0);
+    assert_eq!(b.dropped(), 0);
+    assert_eq!(c.dropped(), 1);
+    drop(q);
+    assert_eq!(a.dropped(), 0);
+    assert_eq!(b.dropped(), 0);
+    assert_eq!(c.dropped(), 1);
+}
+
+#[test]
+fn test_drain_sorted_forget() {
+    let a = CrashTestDummy::new(0);
+    let b = CrashTestDummy::new(1);
+    let c = CrashTestDummy::new(2);
+    let mut q =
+        BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]);
+
+    catch_unwind(AssertUnwindSafe(|| {
+        let mut it = q.drain_sorted();
+        it.next();
+        mem::forget(it);
+    }))
+    .unwrap();
+    // Behaviour after leaking is explicitly unspecified,
+    // so it's fine if these start failing, but probably worth knowing.
+    assert_eq!(q.len(), 2);
+    assert_eq!(a.dropped(), 0);
+    assert_eq!(b.dropped(), 0);
+    assert_eq!(c.dropped(), 1);
+    drop(q);
+    assert_eq!(a.dropped(), 1);
+    assert_eq!(b.dropped(), 1);
+    assert_eq!(c.dropped(), 1);
 }
 
 #[test]
@@ -415,7 +465,7 @@ fn test_retain() {
 #[test]
 #[cfg(not(target_os = "emscripten"))]
 fn panic_safe() {
-    use rand::{seq::SliceRandom, thread_rng};
+    use rand::seq::SliceRandom;
     use std::cmp;
     use std::panic::{self, AssertUnwindSafe};
     use std::sync::atomic::{AtomicUsize, Ordering};
@@ -440,7 +490,7 @@ fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
             self.0.partial_cmp(&other.0)
         }
     }
-    let mut rng = thread_rng();
+    let mut rng = crate::test_helpers::test_rng();
     const DATASZ: usize = 32;
     // Miri is too slow
     let ntest = if cfg!(miri) { 1 } else { 10 };
index 4c372b1d60ac4f8fa7b693b6097bef19ef706985..700b1463bfd51f961e8b7bb2cb43e991c9473d4e 100644 (file)
@@ -1,12 +1,12 @@
-use super::super::testing::crash_test::{CrashTestDummy, Panic};
-use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor};
-use super::super::testing::rng::DeterministicRng;
 use super::Entry::{Occupied, Vacant};
 use super::*;
 use crate::boxed::Box;
 use crate::fmt::Debug;
 use crate::rc::Rc;
 use crate::string::{String, ToString};
+use crate::testing::crash_test::{CrashTestDummy, Panic};
+use crate::testing::ord_chaos::{Cyclic3, Governed, Governor};
+use crate::testing::rng::DeterministicRng;
 use crate::vec::Vec;
 use std::cmp::Ordering;
 use std::convert::TryFrom;
index 9d43ac5c5be5992599fa815d4c9cf6d98c78f9c0..7552f2fc04ce8baf63f9db30ff7c7e07b254e542 100644 (file)
@@ -21,6 +21,3 @@ trait Recover<Q: ?Sized> {
     fn take(&mut self, key: &Q) -> Option<Self::Key>;
     fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
 }
-
-#[cfg(test)]
-mod testing;
index da766b67a328f6b0a0356c28d397005768ff8935..6912466448fab444c6860425ba5970a41ef75a8b 100644 (file)
@@ -318,7 +318,10 @@ impl<BorrowType: marker::BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type>
     pub fn ascend(
         self,
     ) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
-        let _ = BorrowType::TRAVERSAL_PERMIT;
+        const {
+            assert!(BorrowType::TRAVERSAL_PERMIT);
+        }
+
         // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut,
         // there might be outstanding mutable references to values that we must not invalidate.
         let leaf_ptr: *const _ = Self::as_leaf_ptr(&self);
@@ -1003,7 +1006,10 @@ impl<BorrowType: marker::BorrowType, K, V>
     /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should
     /// both, upon success, do nothing.
     pub fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
-        let _ = BorrowType::TRAVERSAL_PERMIT;
+        const {
+            assert!(BorrowType::TRAVERSAL_PERMIT);
+        }
+
         // We need to use raw pointers to nodes because, if BorrowType is
         // marker::ValMut, there might be outstanding mutable references to
         // values that we must not invalidate. There's no worry accessing the
@@ -1666,17 +1672,17 @@ pub enum Dying {}
     pub struct ValMut<'a>(PhantomData<&'a mut ()>);
 
     pub trait BorrowType {
-        // If node references of this borrow type allow traversing to other
-        // nodes in the tree, this constant can be evaluated. Thus reading it
-        // serves as a compile-time assertion.
-        const TRAVERSAL_PERMIT: () = ();
+        /// If node references of this borrow type allow traversing to other
+        /// nodes in the tree, this constant is set to `true`. It can be used
+        /// for a compile-time assertion.
+        const TRAVERSAL_PERMIT: bool = true;
     }
     impl BorrowType for Owned {
-        // Reject evaluation, because traversal isn't needed. Instead traversal
-        // happens using the result of `borrow_mut`.
-        // By disabling traversal, and only creating new references to roots,
-        // we know that every reference of the `Owned` type is to a root node.
-        const TRAVERSAL_PERMIT: () = panic!();
+        /// Reject traversal, because it isn't needed. Instead traversal
+        /// happens using the result of `borrow_mut`.
+        /// By disabling traversal, and only creating new references to roots,
+        /// we know that every reference of the `Owned` type is to a root node.
+        const TRAVERSAL_PERMIT: bool = false;
     }
     impl BorrowType for Dying {}
     impl<'a> BorrowType for Immut<'a> {}
index 502d3e1d1266754a093d26b9c0852a5c5927c20d..7b8d41a603176b07a1e3a6b648ab9cbac577f14d 100644 (file)
@@ -1,6 +1,6 @@
-use super::super::testing::crash_test::{CrashTestDummy, Panic};
-use super::super::testing::rng::DeterministicRng;
 use super::*;
+use crate::testing::crash_test::{CrashTestDummy, Panic};
+use crate::testing::rng::DeterministicRng;
 use crate::vec::Vec;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
diff --git a/library/alloc/src/collections/btree/testing/crash_test.rs b/library/alloc/src/collections/btree/testing/crash_test.rs
deleted file mode 100644 (file)
index bcf5f5f..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-// We avoid relying on anything else in the crate, apart from the `Debug` trait.
-use crate::fmt::Debug;
-use std::cmp::Ordering;
-use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-
-/// A blueprint for crash test dummy instances that monitor particular events.
-/// Some instances may be configured to panic at some point.
-/// Events are `clone`, `drop` or some anonymous `query`.
-///
-/// Crash test dummies are identified and ordered by an id, so they can be used
-/// as keys in a BTreeMap.
-#[derive(Debug)]
-pub struct CrashTestDummy {
-    pub id: usize,
-    cloned: AtomicUsize,
-    dropped: AtomicUsize,
-    queried: AtomicUsize,
-}
-
-impl CrashTestDummy {
-    /// Creates a crash test dummy design. The `id` determines order and equality of instances.
-    pub fn new(id: usize) -> CrashTestDummy {
-        CrashTestDummy {
-            id,
-            cloned: AtomicUsize::new(0),
-            dropped: AtomicUsize::new(0),
-            queried: AtomicUsize::new(0),
-        }
-    }
-
-    /// Creates an instance of a crash test dummy that records what events it experiences
-    /// and optionally panics.
-    pub fn spawn(&self, panic: Panic) -> Instance<'_> {
-        Instance { origin: self, panic }
-    }
-
-    /// Returns how many times instances of the dummy have been cloned.
-    pub fn cloned(&self) -> usize {
-        self.cloned.load(SeqCst)
-    }
-
-    /// Returns how many times instances of the dummy have been dropped.
-    pub fn dropped(&self) -> usize {
-        self.dropped.load(SeqCst)
-    }
-
-    /// Returns how many times instances of the dummy have had their `query` member invoked.
-    pub fn queried(&self) -> usize {
-        self.queried.load(SeqCst)
-    }
-}
-
-#[derive(Debug)]
-pub struct Instance<'a> {
-    origin: &'a CrashTestDummy,
-    panic: Panic,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Panic {
-    Never,
-    InClone,
-    InDrop,
-    InQuery,
-}
-
-impl Instance<'_> {
-    pub fn id(&self) -> usize {
-        self.origin.id
-    }
-
-    /// Some anonymous query, the result of which is already given.
-    pub fn query<R>(&self, result: R) -> R {
-        self.origin.queried.fetch_add(1, SeqCst);
-        if self.panic == Panic::InQuery {
-            panic!("panic in `query`");
-        }
-        result
-    }
-}
-
-impl Clone for Instance<'_> {
-    fn clone(&self) -> Self {
-        self.origin.cloned.fetch_add(1, SeqCst);
-        if self.panic == Panic::InClone {
-            panic!("panic in `clone`");
-        }
-        Self { origin: self.origin, panic: Panic::Never }
-    }
-}
-
-impl Drop for Instance<'_> {
-    fn drop(&mut self) {
-        self.origin.dropped.fetch_add(1, SeqCst);
-        if self.panic == Panic::InDrop {
-            panic!("panic in `drop`");
-        }
-    }
-}
-
-impl PartialOrd for Instance<'_> {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        self.id().partial_cmp(&other.id())
-    }
-}
-
-impl Ord for Instance<'_> {
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.id().cmp(&other.id())
-    }
-}
-
-impl PartialEq for Instance<'_> {
-    fn eq(&self, other: &Self) -> bool {
-        self.id().eq(&other.id())
-    }
-}
-
-impl Eq for Instance<'_> {}
diff --git a/library/alloc/src/collections/btree/testing/mod.rs b/library/alloc/src/collections/btree/testing/mod.rs
deleted file mode 100644 (file)
index 7a094f8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod crash_test;
-pub mod ord_chaos;
-pub mod rng;
diff --git a/library/alloc/src/collections/btree/testing/ord_chaos.rs b/library/alloc/src/collections/btree/testing/ord_chaos.rs
deleted file mode 100644 (file)
index 96ce7c1..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-use std::cell::Cell;
-use std::cmp::Ordering::{self, *};
-use std::ptr;
-
-// Minimal type with an `Ord` implementation violating transitivity.
-#[derive(Debug)]
-pub enum Cyclic3 {
-    A,
-    B,
-    C,
-}
-use Cyclic3::*;
-
-impl PartialOrd for Cyclic3 {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Cyclic3 {
-    fn cmp(&self, other: &Self) -> Ordering {
-        match (self, other) {
-            (A, A) | (B, B) | (C, C) => Equal,
-            (A, B) | (B, C) | (C, A) => Less,
-            (A, C) | (B, A) | (C, B) => Greater,
-        }
-    }
-}
-
-impl PartialEq for Cyclic3 {
-    fn eq(&self, other: &Self) -> bool {
-        self.cmp(&other) == Equal
-    }
-}
-
-impl Eq for Cyclic3 {}
-
-// Controls the ordering of values wrapped by `Governed`.
-#[derive(Debug)]
-pub struct Governor {
-    flipped: Cell<bool>,
-}
-
-impl Governor {
-    pub fn new() -> Self {
-        Governor { flipped: Cell::new(false) }
-    }
-
-    pub fn flip(&self) {
-        self.flipped.set(!self.flipped.get());
-    }
-}
-
-// Type with an `Ord` implementation that forms a total order at any moment
-// (assuming that `T` respects total order), but can suddenly be made to invert
-// that total order.
-#[derive(Debug)]
-pub struct Governed<'a, T>(pub T, pub &'a Governor);
-
-impl<T: Ord> PartialOrd for Governed<'_, T> {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl<T: Ord> Ord for Governed<'_, T> {
-    fn cmp(&self, other: &Self) -> Ordering {
-        assert!(ptr::eq(self.1, other.1));
-        let ord = self.0.cmp(&other.0);
-        if self.1.flipped.get() { ord.reverse() } else { ord }
-    }
-}
-
-impl<T: PartialEq> PartialEq for Governed<'_, T> {
-    fn eq(&self, other: &Self) -> bool {
-        assert!(ptr::eq(self.1, other.1));
-        self.0.eq(&other.0)
-    }
-}
-
-impl<T: Eq> Eq for Governed<'_, T> {}
diff --git a/library/alloc/src/collections/btree/testing/rng.rs b/library/alloc/src/collections/btree/testing/rng.rs
deleted file mode 100644 (file)
index ecf543b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/// XorShiftRng
-pub struct DeterministicRng {
-    count: usize,
-    x: u32,
-    y: u32,
-    z: u32,
-    w: u32,
-}
-
-impl DeterministicRng {
-    pub fn new() -> Self {
-        DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
-    }
-
-    /// Guarantees that each returned number is unique.
-    pub fn next(&mut self) -> u32 {
-        self.count += 1;
-        assert!(self.count <= 70029);
-        let x = self.x;
-        let t = x ^ (x << 11);
-        self.x = self.y;
-        self.y = self.z;
-        self.z = self.w;
-        let w_ = self.w;
-        self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
-        self.w
-    }
-}
index f8fbfa1bfbc87bdc171dfc785415779dedb2809e..04594d55b6abf1834eea51ac3f19ee0e2039a123 100644 (file)
@@ -1,10 +1,11 @@
 use super::*;
+use crate::testing::crash_test::{CrashTestDummy, Panic};
 use crate::vec::Vec;
 
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::thread;
 
-use rand::{thread_rng, RngCore};
+use rand::RngCore;
 
 #[test]
 fn test_basic() {
@@ -480,12 +481,12 @@ fn test_split_off_2() {
     }
 }
 
-fn fuzz_test(sz: i32) {
+fn fuzz_test(sz: i32, rng: &mut impl RngCore) {
     let mut m: LinkedList<_> = LinkedList::new();
     let mut v = vec![];
     for i in 0..sz {
         check_links(&m);
-        let r: u8 = thread_rng().next_u32() as u8;
+        let r: u8 = rng.next_u32() as u8;
         match r % 6 {
             0 => {
                 m.pop_back();
@@ -520,11 +521,12 @@ fn fuzz_test(sz: i32) {
 
 #[test]
 fn test_fuzz() {
+    let mut rng = crate::test_helpers::test_rng();
     for _ in 0..25 {
-        fuzz_test(3);
-        fuzz_test(16);
+        fuzz_test(3, &mut rng);
+        fuzz_test(16, &mut rng);
         #[cfg(not(miri))] // Miri is too slow
-        fuzz_test(189);
+        fuzz_test(189, &mut rng);
     }
 }
 
@@ -984,35 +986,34 @@ fn drain_filter_complex() {
 
 #[test]
 fn drain_filter_drop_panic_leak() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
+    let d0 = CrashTestDummy::new(0);
+    let d1 = CrashTestDummy::new(1);
+    let d2 = CrashTestDummy::new(2);
+    let d3 = CrashTestDummy::new(3);
+    let d4 = CrashTestDummy::new(4);
+    let d5 = CrashTestDummy::new(5);
+    let d6 = CrashTestDummy::new(6);
+    let d7 = CrashTestDummy::new(7);
     let mut q = LinkedList::new();
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_front(D(false));
-    q.push_front(D(true));
-    q.push_front(D(false));
-
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
-
-    assert_eq!(unsafe { DROPS }, 8);
+    q.push_back(d3.spawn(Panic::Never));
+    q.push_back(d4.spawn(Panic::Never));
+    q.push_back(d5.spawn(Panic::Never));
+    q.push_back(d6.spawn(Panic::Never));
+    q.push_back(d7.spawn(Panic::Never));
+    q.push_front(d2.spawn(Panic::Never));
+    q.push_front(d1.spawn(Panic::InDrop));
+    q.push_front(d0.spawn(Panic::Never));
+
+    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err();
+
+    assert_eq!(d0.dropped(), 1);
+    assert_eq!(d1.dropped(), 1);
+    assert_eq!(d2.dropped(), 1);
+    assert_eq!(d3.dropped(), 1);
+    assert_eq!(d4.dropped(), 1);
+    assert_eq!(d5.dropped(), 1);
+    assert_eq!(d6.dropped(), 1);
+    assert_eq!(d7.dropped(), 1);
     assert!(q.is_empty());
 }
 
index c955db46d29fe11dae1fe3f2d38deed47dbe00ea..451e4936bc50eb8c29b6580ea37e8bc641f25acd 100644 (file)
@@ -636,6 +636,7 @@ pub(crate) unsafe fn from_contiguous_raw_parts_in(
     /// buf.push_back(3);
     /// buf.push_back(4);
     /// buf.push_back(5);
+    /// buf.push_back(6);
     /// assert_eq!(buf.get(1), Some(&4));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -661,10 +662,11 @@ pub fn get(&self, index: usize) -> Option<&T> {
     /// buf.push_back(3);
     /// buf.push_back(4);
     /// buf.push_back(5);
+    /// buf.push_back(6);
+    /// assert_eq!(buf[1], 4);
     /// if let Some(elem) = buf.get_mut(1) {
     ///     *elem = 7;
     /// }
-    ///
     /// assert_eq!(buf[1], 7);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2821,9 +2823,9 @@ impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
     /// [`Vec<T>`]: crate::vec::Vec
     /// [`VecDeque<T>`]: crate::collections::VecDeque
     ///
-    /// In its current implementation, this is a very cheap
-    /// conversion. This isn't yet a guarantee though, and
-    /// shouldn't be relied on.
+    /// This conversion is guaranteed to run in *O*(1) time
+    /// and to not re-allocate the `Vec`'s buffer or allocate
+    /// any additional memory.
     #[inline]
     fn from(other: Vec<T, A>) -> Self {
         let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc();
index 96960d43f5820a26121f26bb8fb1236116fccd0c..4e812529c2cc846d7934672a05202a0eb9db7218 100644 (file)
@@ -3,7 +3,7 @@
 //! This library provides smart pointers and collections for managing
 //! heap-allocated values.
 //!
-//! This library, like libcore, normally doesn’t need to be used directly
+//! This library, like core, normally doesn’t need to be used directly
 //! since its contents are re-exported in the [`std` crate](../std/index.html).
 //! Crates that use the `#![no_std]` attribute however will typically
 //! not depend on `std`, so they’d use this crate instead.
@@ -75,7 +75,7 @@
 ))]
 #![no_std]
 #![needs_allocator]
-// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
+// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
 // able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
 // rustc itself never sets the feature, so this line has no affect there.
 #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_refs_to_cell)]
 #![feature(core_intrinsics)]
+#![feature(core_panic)]
 #![feature(const_eval_select)]
 #![feature(const_pin)]
 #![feature(const_waker)]
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
 #![feature(hasher_prefixfree_extras)]
+#![feature(inline_const)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
 #![feature(try_trait_v2)]
-#![cfg_attr(not(bootstrap), feature(tuple_trait))]
+#![feature(tuple_trait)]
 #![feature(unchecked_math)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
 #![feature(unsized_fn_params)]
 #![feature(c_unwind)]
 #![feature(with_negative_coherence)]
+#![cfg_attr(test, feature(panic_update_hook))]
 //
 // Rustdoc features:
 #![feature(doc_cfg)]
 extern crate std;
 #[cfg(test)]
 extern crate test;
+#[cfg(test)]
+mod testing;
 
 // Module with internal macros used by other modules (needs to be included before other modules).
 #[macro_use]
@@ -251,3 +256,20 @@ mod boxed {
 pub mod __export {
     pub use core::format_args;
 }
+
+#[cfg(test)]
+#[allow(dead_code)] // Not used in all configurations
+pub(crate) mod test_helpers {
+    /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+    /// seed not being the same for every RNG invocation too.
+    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+        use std::hash::{BuildHasher, Hash, Hasher};
+        let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+        std::panic::Location::caller().hash(&mut hasher);
+        let hc64 = hasher.finish();
+        let seed_vec =
+            hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
+        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+        rand::SeedableRng::from_seed(seed)
+    }
+}
index 80a5913daa6e032720e832141d4105c6d8311106..c1d853ed652160149e6911c5577e8cc93891f1a9 100644 (file)
@@ -2561,7 +2561,7 @@ fn clone(&self) -> Weak<T> {
 }
 
 #[stable(feature = "rc_weak", since = "1.4.0")]
-impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
+impl<T: ?Sized> fmt::Debug for Weak<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "(Weak)")
     }
index 1b61ede3476c336c3112867a32253dc86ee219ea..e9886fc5717990ec4a93feafa5901aa4235ca9fd 100644 (file)
@@ -28,6 +28,9 @@
 use crate::boxed::Box;
 use crate::vec::Vec;
 
+#[cfg(test)]
+mod tests;
+
 #[unstable(feature = "slice_range", issue = "76393")]
 pub use core::slice::range;
 #[unstable(feature = "array_chunks", issue = "74985")]
@@ -653,7 +656,7 @@ pub fn to_ascii_lowercase(&self) -> Vec<u8> {
 ///
 /// ```error
 /// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predica
-///    --> src/liballoc/slice.rs:608:6
+///    --> library/alloc/src/slice.rs:608:6
 ///     |
 /// 608 | impl<T: Clone, V: Borrow<[T]>> Concat for [V] {
 ///     |      ^ unconstrained type parameter
diff --git a/library/alloc/src/slice/tests.rs b/library/alloc/src/slice/tests.rs
new file mode 100644 (file)
index 0000000..f674530
--- /dev/null
@@ -0,0 +1,359 @@
+use crate::borrow::ToOwned;
+use crate::rc::Rc;
+use crate::string::ToString;
+use crate::test_helpers::test_rng;
+use crate::vec::Vec;
+
+use core::cell::Cell;
+use core::cmp::Ordering::{self, Equal, Greater, Less};
+use core::convert::identity;
+use core::fmt;
+use core::mem;
+use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use rand::{distributions::Standard, prelude::*, Rng, RngCore};
+use std::panic;
+
+macro_rules! do_test {
+    ($input:ident, $func:ident) => {
+        let len = $input.len();
+
+        // Work out the total number of comparisons required to sort
+        // this array...
+        let mut count = 0usize;
+        $input.to_owned().$func(|a, b| {
+            count += 1;
+            a.cmp(b)
+        });
+
+        // ... and then panic on each and every single one.
+        for panic_countdown in 0..count {
+            // Refresh the counters.
+            VERSIONS.store(0, Relaxed);
+            for i in 0..len {
+                DROP_COUNTS[i].store(0, Relaxed);
+            }
+
+            let v = $input.to_owned();
+            let _ = std::panic::catch_unwind(move || {
+                let mut v = v;
+                let mut panic_countdown = panic_countdown;
+                v.$func(|a, b| {
+                    if panic_countdown == 0 {
+                        SILENCE_PANIC.with(|s| s.set(true));
+                        panic!();
+                    }
+                    panic_countdown -= 1;
+                    a.cmp(b)
+                })
+            });
+
+            // Check that the number of things dropped is exactly
+            // what we expect (i.e., the contents of `v`).
+            for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
+                let count = c.load(Relaxed);
+                assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
+            }
+
+            // Check that the most recent versions of values were dropped.
+            assert_eq!(VERSIONS.load(Relaxed), 0);
+        }
+    };
+}
+
+const MAX_LEN: usize = 80;
+
+static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
+    // FIXME(RFC 1109): AtomicUsize is not Copy.
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+    AtomicUsize::new(0),
+];
+
+static VERSIONS: AtomicUsize = AtomicUsize::new(0);
+
+#[derive(Clone, Eq)]
+struct DropCounter {
+    x: u32,
+    id: usize,
+    version: Cell<usize>,
+}
+
+impl PartialEq for DropCounter {
+    fn eq(&self, other: &Self) -> bool {
+        self.partial_cmp(other) == Some(Ordering::Equal)
+    }
+}
+
+impl PartialOrd for DropCounter {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.version.set(self.version.get() + 1);
+        other.version.set(other.version.get() + 1);
+        VERSIONS.fetch_add(2, Relaxed);
+        self.x.partial_cmp(&other.x)
+    }
+}
+
+impl Ord for DropCounter {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.partial_cmp(other).unwrap()
+    }
+}
+
+impl Drop for DropCounter {
+    fn drop(&mut self) {
+        DROP_COUNTS[self.id].fetch_add(1, Relaxed);
+        VERSIONS.fetch_sub(self.version.get(), Relaxed);
+    }
+}
+
+std::thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)] // no threads
+fn panic_safe() {
+    panic::update_hook(move |prev, info| {
+        if !SILENCE_PANIC.with(|s| s.get()) {
+            prev(info);
+        }
+    });
+
+    let mut rng = test_rng();
+
+    // Miri is too slow (but still need to `chain` to make the types match)
+    let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
+    let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
+
+    for len in lens {
+        for &modulus in moduli {
+            for &has_runs in &[false, true] {
+                let mut input = (0..len)
+                    .map(|id| DropCounter {
+                        x: rng.next_u32() % modulus,
+                        id: id,
+                        version: Cell::new(0),
+                    })
+                    .collect::<Vec<_>>();
+
+                if has_runs {
+                    for c in &mut input {
+                        c.x = c.id as u32;
+                    }
+
+                    for _ in 0..5 {
+                        let a = rng.gen::<usize>() % len;
+                        let b = rng.gen::<usize>() % len;
+                        if a < b {
+                            input[a..b].reverse();
+                        } else {
+                            input.swap(a, b);
+                        }
+                    }
+                }
+
+                do_test!(input, sort_by);
+                do_test!(input, sort_unstable_by);
+            }
+        }
+    }
+
+    // Set default panic hook again.
+    drop(panic::take_hook());
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_sort() {
+    let mut rng = test_rng();
+
+    for len in (2..25).chain(500..510) {
+        for &modulus in &[5, 10, 100, 1000] {
+            for _ in 0..10 {
+                let orig: Vec<_> = (&mut rng)
+                    .sample_iter::<i32, _>(&Standard)
+                    .map(|x| x % modulus)
+                    .take(len)
+                    .collect();
+
+                // Sort in default order.
+                let mut v = orig.clone();
+                v.sort();
+                assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+                // Sort in ascending order.
+                let mut v = orig.clone();
+                v.sort_by(|a, b| a.cmp(b));
+                assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+                // Sort in descending order.
+                let mut v = orig.clone();
+                v.sort_by(|a, b| b.cmp(a));
+                assert!(v.windows(2).all(|w| w[0] >= w[1]));
+
+                // Sort in lexicographic order.
+                let mut v1 = orig.clone();
+                let mut v2 = orig.clone();
+                v1.sort_by_key(|x| x.to_string());
+                v2.sort_by_cached_key(|x| x.to_string());
+                assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
+                assert!(v1 == v2);
+
+                // Sort with many pre-sorted runs.
+                let mut v = orig.clone();
+                v.sort();
+                v.reverse();
+                for _ in 0..5 {
+                    let a = rng.gen::<usize>() % len;
+                    let b = rng.gen::<usize>() % len;
+                    if a < b {
+                        v[a..b].reverse();
+                    } else {
+                        v.swap(a, b);
+                    }
+                }
+                v.sort();
+                assert!(v.windows(2).all(|w| w[0] <= w[1]));
+            }
+        }
+    }
+
+    // Sort using a completely random comparison function.
+    // This will reorder the elements *somehow*, but won't panic.
+    let mut v = [0; 500];
+    for i in 0..v.len() {
+        v[i] = i as i32;
+    }
+    v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
+    v.sort();
+    for i in 0..v.len() {
+        assert_eq!(v[i], i as i32);
+    }
+
+    // Should not panic.
+    [0i32; 0].sort();
+    [(); 10].sort();
+    [(); 100].sort();
+
+    let mut v = [0xDEADBEEFu64];
+    v.sort();
+    assert!(v == [0xDEADBEEF]);
+}
+
+#[test]
+fn test_sort_stability() {
+    // Miri is too slow
+    let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
+    let rounds = if cfg!(miri) { 1 } else { 10 };
+
+    let mut rng = test_rng();
+    for len in (2..25).chain(large_range) {
+        for _ in 0..rounds {
+            let mut counts = [0; 10];
+
+            // create a vector like [(6, 1), (5, 1), (6, 2), ...],
+            // where the first item of each tuple is random, but
+            // the second item represents which occurrence of that
+            // number this element is, i.e., the second elements
+            // will occur in sorted order.
+            let orig: Vec<_> = (0..len)
+                .map(|_| {
+                    let n = rng.gen::<usize>() % 10;
+                    counts[n] += 1;
+                    (n, counts[n])
+                })
+                .collect();
+
+            let mut v = orig.clone();
+            // Only sort on the first element, so an unstable sort
+            // may mix up the counts.
+            v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
+
+            // This comparison includes the count (the second item
+            // of the tuple), so elements with equal first items
+            // will need to be ordered with increasing
+            // counts... i.e., exactly asserting that this sort is
+            // stable.
+            assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+            let mut v = orig.clone();
+            v.sort_by_cached_key(|&(x, _)| x);
+            assert!(v.windows(2).all(|w| w[0] <= w[1]));
+        }
+    }
+}
index 7a8e6f088f3acc5f3c63b1695e4b6d9907d2ec5c..24f1b3a1c87509888ff5cc3dacf45679732942c0 100644 (file)
 /// [`as_str()`]: String::as_str
 #[derive(PartialOrd, Eq, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(all(not(bootstrap), not(test)), lang = "String")]
+#[cfg_attr(not(test), lang = "String")]
 pub struct String {
     vec: Vec<u8>,
 }
@@ -2678,7 +2678,7 @@ fn from(s: &String) -> String {
     }
 }
 
-// note: test pulls in libstd, which causes errors here
+// note: test pulls in std, which causes errors here
 #[cfg(not(test))]
 #[stable(feature = "string_from_box", since = "1.18.0")]
 impl From<Box<str>> for String {
index ddcd863aa3e338352b8d0a5ff9956e42cdfb0b10..d833d4d1dfbd327a5f53b606498e5e717cbcae69 100644 (file)
@@ -312,7 +312,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
 
 #[stable(feature = "arc_weak", since = "1.4.0")]
-impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
+impl<T: ?Sized> fmt::Debug for Weak<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "(Weak)")
     }
diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloc/src/testing/crash_test.rs
new file mode 100644 (file)
index 0000000..bcf5f5f
--- /dev/null
@@ -0,0 +1,119 @@
+// We avoid relying on anything else in the crate, apart from the `Debug` trait.
+use crate::fmt::Debug;
+use std::cmp::Ordering;
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+/// A blueprint for crash test dummy instances that monitor particular events.
+/// Some instances may be configured to panic at some point.
+/// Events are `clone`, `drop` or some anonymous `query`.
+///
+/// Crash test dummies are identified and ordered by an id, so they can be used
+/// as keys in a BTreeMap.
+#[derive(Debug)]
+pub struct CrashTestDummy {
+    pub id: usize,
+    cloned: AtomicUsize,
+    dropped: AtomicUsize,
+    queried: AtomicUsize,
+}
+
+impl CrashTestDummy {
+    /// Creates a crash test dummy design. The `id` determines order and equality of instances.
+    pub fn new(id: usize) -> CrashTestDummy {
+        CrashTestDummy {
+            id,
+            cloned: AtomicUsize::new(0),
+            dropped: AtomicUsize::new(0),
+            queried: AtomicUsize::new(0),
+        }
+    }
+
+    /// Creates an instance of a crash test dummy that records what events it experiences
+    /// and optionally panics.
+    pub fn spawn(&self, panic: Panic) -> Instance<'_> {
+        Instance { origin: self, panic }
+    }
+
+    /// Returns how many times instances of the dummy have been cloned.
+    pub fn cloned(&self) -> usize {
+        self.cloned.load(SeqCst)
+    }
+
+    /// Returns how many times instances of the dummy have been dropped.
+    pub fn dropped(&self) -> usize {
+        self.dropped.load(SeqCst)
+    }
+
+    /// Returns how many times instances of the dummy have had their `query` member invoked.
+    pub fn queried(&self) -> usize {
+        self.queried.load(SeqCst)
+    }
+}
+
+#[derive(Debug)]
+pub struct Instance<'a> {
+    origin: &'a CrashTestDummy,
+    panic: Panic,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Panic {
+    Never,
+    InClone,
+    InDrop,
+    InQuery,
+}
+
+impl Instance<'_> {
+    pub fn id(&self) -> usize {
+        self.origin.id
+    }
+
+    /// Some anonymous query, the result of which is already given.
+    pub fn query<R>(&self, result: R) -> R {
+        self.origin.queried.fetch_add(1, SeqCst);
+        if self.panic == Panic::InQuery {
+            panic!("panic in `query`");
+        }
+        result
+    }
+}
+
+impl Clone for Instance<'_> {
+    fn clone(&self) -> Self {
+        self.origin.cloned.fetch_add(1, SeqCst);
+        if self.panic == Panic::InClone {
+            panic!("panic in `clone`");
+        }
+        Self { origin: self.origin, panic: Panic::Never }
+    }
+}
+
+impl Drop for Instance<'_> {
+    fn drop(&mut self) {
+        self.origin.dropped.fetch_add(1, SeqCst);
+        if self.panic == Panic::InDrop {
+            panic!("panic in `drop`");
+        }
+    }
+}
+
+impl PartialOrd for Instance<'_> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.id().partial_cmp(&other.id())
+    }
+}
+
+impl Ord for Instance<'_> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.id().cmp(&other.id())
+    }
+}
+
+impl PartialEq for Instance<'_> {
+    fn eq(&self, other: &Self) -> bool {
+        self.id().eq(&other.id())
+    }
+}
+
+impl Eq for Instance<'_> {}
diff --git a/library/alloc/src/testing/mod.rs b/library/alloc/src/testing/mod.rs
new file mode 100644 (file)
index 0000000..7a094f8
--- /dev/null
@@ -0,0 +1,3 @@
+pub mod crash_test;
+pub mod ord_chaos;
+pub mod rng;
diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloc/src/testing/ord_chaos.rs
new file mode 100644 (file)
index 0000000..96ce7c1
--- /dev/null
@@ -0,0 +1,81 @@
+use std::cell::Cell;
+use std::cmp::Ordering::{self, *};
+use std::ptr;
+
+// Minimal type with an `Ord` implementation violating transitivity.
+#[derive(Debug)]
+pub enum Cyclic3 {
+    A,
+    B,
+    C,
+}
+use Cyclic3::*;
+
+impl PartialOrd for Cyclic3 {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Cyclic3 {
+    fn cmp(&self, other: &Self) -> Ordering {
+        match (self, other) {
+            (A, A) | (B, B) | (C, C) => Equal,
+            (A, B) | (B, C) | (C, A) => Less,
+            (A, C) | (B, A) | (C, B) => Greater,
+        }
+    }
+}
+
+impl PartialEq for Cyclic3 {
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(&other) == Equal
+    }
+}
+
+impl Eq for Cyclic3 {}
+
+// Controls the ordering of values wrapped by `Governed`.
+#[derive(Debug)]
+pub struct Governor {
+    flipped: Cell<bool>,
+}
+
+impl Governor {
+    pub fn new() -> Self {
+        Governor { flipped: Cell::new(false) }
+    }
+
+    pub fn flip(&self) {
+        self.flipped.set(!self.flipped.get());
+    }
+}
+
+// Type with an `Ord` implementation that forms a total order at any moment
+// (assuming that `T` respects total order), but can suddenly be made to invert
+// that total order.
+#[derive(Debug)]
+pub struct Governed<'a, T>(pub T, pub &'a Governor);
+
+impl<T: Ord> PartialOrd for Governed<'_, T> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<T: Ord> Ord for Governed<'_, T> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        assert!(ptr::eq(self.1, other.1));
+        let ord = self.0.cmp(&other.0);
+        if self.1.flipped.get() { ord.reverse() } else { ord }
+    }
+}
+
+impl<T: PartialEq> PartialEq for Governed<'_, T> {
+    fn eq(&self, other: &Self) -> bool {
+        assert!(ptr::eq(self.1, other.1));
+        self.0.eq(&other.0)
+    }
+}
+
+impl<T: Eq> Eq for Governed<'_, T> {}
diff --git a/library/alloc/src/testing/rng.rs b/library/alloc/src/testing/rng.rs
new file mode 100644 (file)
index 0000000..ecf543b
--- /dev/null
@@ -0,0 +1,28 @@
+/// XorShiftRng
+pub struct DeterministicRng {
+    count: usize,
+    x: u32,
+    y: u32,
+    z: u32,
+    w: u32,
+}
+
+impl DeterministicRng {
+    pub fn new() -> Self {
+        DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
+    }
+
+    /// Guarantees that each returned number is unique.
+    pub fn next(&mut self) -> u32 {
+        self.count += 1;
+        assert!(self.count <= 70029);
+        let x = self.x;
+        let t = x ^ (x << 11);
+        self.x = self.y;
+        self.y = self.z;
+        self.z = self.w;
+        let w_ = self.w;
+        self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
+        self.w
+    }
+}
index ba34ab6800fad4cdd9f6e8be14a63eca335aac17..36cfac8ee9e17da0dde403e785c0a09efd324898 100644 (file)
 /// vec[0] = 7;
 /// assert_eq!(vec[0], 7);
 ///
-/// vec.extend([1, 2, 3].iter().copied());
+/// vec.extend([1, 2, 3]);
 ///
 /// for x in &vec {
 ///     println!("{x}");
@@ -490,6 +490,8 @@ pub fn with_capacity(capacity: usize) -> Self {
     /// This is highly unsafe, due to the number of invariants that aren't
     /// checked:
     ///
+    /// * `ptr` must have been allocated using the global allocator, such as via
+    ///   the [`alloc::alloc`] function.
     /// * `T` needs to have the same alignment as what `ptr` was allocated with.
     ///   (`T` having a less strict alignment is not sufficient, the alignment really
     ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
@@ -526,6 +528,7 @@ pub fn with_capacity(capacity: usize) -> Self {
     /// function.
     ///
     /// [`String`]: crate::string::String
+    /// [`alloc::alloc`]: crate::alloc::alloc
     /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
     ///
     /// # Examples
@@ -681,6 +684,7 @@ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
     /// This is highly unsafe, due to the number of invariants that aren't
     /// checked:
     ///
+    /// * `ptr` must be [*currently allocated*] via the given allocator `alloc`.
     /// * `T` needs to have the same alignment as what `ptr` was allocated with.
     ///   (`T` having a less strict alignment is not sufficient, the alignment really
     ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
@@ -714,6 +718,7 @@ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
     ///
     /// [`String`]: crate::string::String
     /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+    /// [*currently allocated*]: crate::alloc::Allocator#currently-allocated-memory
     /// [*fit*]: crate::alloc::Allocator#memory-fitting
     ///
     /// # Examples
@@ -3191,7 +3196,7 @@ fn from(s: Cow<'a, [T]>) -> Vec<T> {
     }
 }
 
-// note: test pulls in libstd, which causes errors here
+// note: test pulls in std, which causes errors here
 #[cfg(not(test))]
 #[stable(feature = "vec_from_box", since = "1.18.0")]
 impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
@@ -3209,7 +3214,7 @@ fn from(s: Box<[T], A>) -> Self {
     }
 }
 
-// note: test pulls in libstd, which causes errors here
+// note: test pulls in std, which causes errors here
 #[cfg(not(no_global_oom_handling))]
 #[cfg(not(test))]
 #[stable(feature = "box_from_vec", since = "1.20.0")]
index 8ff5f0abe73dd013aa31bc76d3d03f6475c97816..879e32b3fa309ce7190f94dc8fd167e9900a4229 100644 (file)
@@ -32,7 +32,7 @@ fn test_btree_map() {
     //         spawn(f());
     //     }
     //
-    // where with some unintentionally overconstrained Send impls in liballoc's
+    // where with some unintentionally overconstrained Send impls in alloc's
     // internals, the future might incorrectly not be Send even though every
     // single type involved in the program is Send and Sync.
     require_send_sync(async {
index 21f894343be097394aee870a5b71f83fec2f64ab..0693beb48c402130a58f7ce54c18291d660bde0f 100644 (file)
@@ -1,15 +1,9 @@
-use std::cell::Cell;
-use std::cmp::Ordering::{self, Equal, Greater, Less};
+use std::cmp::Ordering::{Equal, Greater, Less};
 use std::convert::identity;
 use std::fmt;
 use std::mem;
 use std::panic;
 use std::rc::Rc;
-use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-
-use rand::distributions::Standard;
-use rand::seq::SliceRandom;
-use rand::{thread_rng, Rng, RngCore};
 
 fn square(n: usize) -> usize {
     n * n
@@ -388,123 +382,6 @@ fn test_reverse() {
     assert_eq!(v, (-50..51i16).rev().collect::<Vec<_>>());
 }
 
-#[test]
-#[cfg_attr(miri, ignore)] // Miri is too slow
-fn test_sort() {
-    let mut rng = thread_rng();
-
-    for len in (2..25).chain(500..510) {
-        for &modulus in &[5, 10, 100, 1000] {
-            for _ in 0..10 {
-                let orig: Vec<_> =
-                    rng.sample_iter::<i32, _>(&Standard).map(|x| x % modulus).take(len).collect();
-
-                // Sort in default order.
-                let mut v = orig.clone();
-                v.sort();
-                assert!(v.windows(2).all(|w| w[0] <= w[1]));
-
-                // Sort in ascending order.
-                let mut v = orig.clone();
-                v.sort_by(|a, b| a.cmp(b));
-                assert!(v.windows(2).all(|w| w[0] <= w[1]));
-
-                // Sort in descending order.
-                let mut v = orig.clone();
-                v.sort_by(|a, b| b.cmp(a));
-                assert!(v.windows(2).all(|w| w[0] >= w[1]));
-
-                // Sort in lexicographic order.
-                let mut v1 = orig.clone();
-                let mut v2 = orig.clone();
-                v1.sort_by_key(|x| x.to_string());
-                v2.sort_by_cached_key(|x| x.to_string());
-                assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
-                assert!(v1 == v2);
-
-                // Sort with many pre-sorted runs.
-                let mut v = orig.clone();
-                v.sort();
-                v.reverse();
-                for _ in 0..5 {
-                    let a = rng.gen::<usize>() % len;
-                    let b = rng.gen::<usize>() % len;
-                    if a < b {
-                        v[a..b].reverse();
-                    } else {
-                        v.swap(a, b);
-                    }
-                }
-                v.sort();
-                assert!(v.windows(2).all(|w| w[0] <= w[1]));
-            }
-        }
-    }
-
-    // Sort using a completely random comparison function.
-    // This will reorder the elements *somehow*, but won't panic.
-    let mut v = [0; 500];
-    for i in 0..v.len() {
-        v[i] = i as i32;
-    }
-    v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
-    v.sort();
-    for i in 0..v.len() {
-        assert_eq!(v[i], i as i32);
-    }
-
-    // Should not panic.
-    [0i32; 0].sort();
-    [(); 10].sort();
-    [(); 100].sort();
-
-    let mut v = [0xDEADBEEFu64];
-    v.sort();
-    assert!(v == [0xDEADBEEF]);
-}
-
-#[test]
-fn test_sort_stability() {
-    // Miri is too slow
-    let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
-    let rounds = if cfg!(miri) { 1 } else { 10 };
-
-    for len in (2..25).chain(large_range) {
-        for _ in 0..rounds {
-            let mut counts = [0; 10];
-
-            // create a vector like [(6, 1), (5, 1), (6, 2), ...],
-            // where the first item of each tuple is random, but
-            // the second item represents which occurrence of that
-            // number this element is, i.e., the second elements
-            // will occur in sorted order.
-            let orig: Vec<_> = (0..len)
-                .map(|_| {
-                    let n = thread_rng().gen::<usize>() % 10;
-                    counts[n] += 1;
-                    (n, counts[n])
-                })
-                .collect();
-
-            let mut v = orig.clone();
-            // Only sort on the first element, so an unstable sort
-            // may mix up the counts.
-            v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
-
-            // This comparison includes the count (the second item
-            // of the tuple), so elements with equal first items
-            // will need to be ordered with increasing
-            // counts... i.e., exactly asserting that this sort is
-            // stable.
-            assert!(v.windows(2).all(|w| w[0] <= w[1]));
-
-            let mut v = orig.clone();
-            v.sort_by_cached_key(|&(x, _)| x);
-            assert!(v.windows(2).all(|w| w[0] <= w[1]));
-        }
-    }
-}
-
 #[test]
 fn test_rotate_left() {
     let expected: Vec<_> = (0..13).collect();
@@ -1608,230 +1485,6 @@ fn test_copy_from_slice_dst_shorter() {
     dst.copy_from_slice(&src);
 }
 
-const MAX_LEN: usize = 80;
-
-static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
-    // FIXME(RFC 1109): AtomicUsize is not Copy.
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-    AtomicUsize::new(0),
-];
-
-static VERSIONS: AtomicUsize = AtomicUsize::new(0);
-
-#[derive(Clone, Eq)]
-struct DropCounter {
-    x: u32,
-    id: usize,
-    version: Cell<usize>,
-}
-
-impl PartialEq for DropCounter {
-    fn eq(&self, other: &Self) -> bool {
-        self.partial_cmp(other) == Some(Ordering::Equal)
-    }
-}
-
-impl PartialOrd for DropCounter {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        self.version.set(self.version.get() + 1);
-        other.version.set(other.version.get() + 1);
-        VERSIONS.fetch_add(2, Relaxed);
-        self.x.partial_cmp(&other.x)
-    }
-}
-
-impl Ord for DropCounter {
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.partial_cmp(other).unwrap()
-    }
-}
-
-impl Drop for DropCounter {
-    fn drop(&mut self) {
-        DROP_COUNTS[self.id].fetch_add(1, Relaxed);
-        VERSIONS.fetch_sub(self.version.get(), Relaxed);
-    }
-}
-
-macro_rules! test {
-    ($input:ident, $func:ident) => {
-        let len = $input.len();
-
-        // Work out the total number of comparisons required to sort
-        // this array...
-        let mut count = 0usize;
-        $input.to_owned().$func(|a, b| {
-            count += 1;
-            a.cmp(b)
-        });
-
-        // ... and then panic on each and every single one.
-        for panic_countdown in 0..count {
-            // Refresh the counters.
-            VERSIONS.store(0, Relaxed);
-            for i in 0..len {
-                DROP_COUNTS[i].store(0, Relaxed);
-            }
-
-            let v = $input.to_owned();
-            let _ = std::panic::catch_unwind(move || {
-                let mut v = v;
-                let mut panic_countdown = panic_countdown;
-                v.$func(|a, b| {
-                    if panic_countdown == 0 {
-                        SILENCE_PANIC.with(|s| s.set(true));
-                        panic!();
-                    }
-                    panic_countdown -= 1;
-                    a.cmp(b)
-                })
-            });
-
-            // Check that the number of things dropped is exactly
-            // what we expect (i.e., the contents of `v`).
-            for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
-                let count = c.load(Relaxed);
-                assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
-            }
-
-            // Check that the most recent versions of values were dropped.
-            assert_eq!(VERSIONS.load(Relaxed), 0);
-        }
-    };
-}
-
-thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
-
-#[test]
-#[cfg_attr(target_os = "emscripten", ignore)] // no threads
-fn panic_safe() {
-    panic::update_hook(move |prev, info| {
-        if !SILENCE_PANIC.with(|s| s.get()) {
-            prev(info);
-        }
-    });
-
-    let mut rng = thread_rng();
-
-    // Miri is too slow (but still need to `chain` to make the types match)
-    let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
-    let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
-
-    for len in lens {
-        for &modulus in moduli {
-            for &has_runs in &[false, true] {
-                let mut input = (0..len)
-                    .map(|id| DropCounter {
-                        x: rng.next_u32() % modulus,
-                        id: id,
-                        version: Cell::new(0),
-                    })
-                    .collect::<Vec<_>>();
-
-                if has_runs {
-                    for c in &mut input {
-                        c.x = c.id as u32;
-                    }
-
-                    for _ in 0..5 {
-                        let a = rng.gen::<usize>() % len;
-                        let b = rng.gen::<usize>() % len;
-                        if a < b {
-                            input[a..b].reverse();
-                        } else {
-                            input.swap(a, b);
-                        }
-                    }
-                }
-
-                test!(input, sort_by);
-                test!(input, sort_unstable_by);
-            }
-        }
-    }
-
-    // Set default panic hook again.
-    drop(panic::take_hook());
-}
-
 #[test]
 fn repeat_generic_slice() {
     assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]);
index 2a7df9556cfe194d9925a70b7414ad7893241ef5..3dc8c84e0bfde0837d4623c05fdd33e604c5a308 100644 (file)
@@ -24,8 +24,8 @@ path = "benches/lib.rs"
 test = true
 
 [dev-dependencies]
-rand = "0.7"
-rand_xorshift = "0.2"
+rand = { version = "0.8.5", default-features = false }
+rand_xorshift = { version = "0.3.0", default-features = false }
 
 [features]
 # Make panics and failed asserts immediately abort without formatting any message
index 3c01e2998cd2f02d4a5c2e8fe49a3fd402793467..bb61224b5baadc15acdeb163d084657009b9726f 100644 (file)
@@ -21,7 +21,7 @@ fn $random(bench: &mut Bencher) {
             /* Exponentially distributed random numbers from the whole range of the type.  */
             let numbers: Vec<$t> = (0..256)
                 .map(|_| {
-                    let x = rng.gen::<$t>() >> rng.gen_range(0<$t>::BITS);
+                    let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS);
                     if x != 0 { x } else { 1 }
                 })
                 .collect();
@@ -38,7 +38,7 @@ fn $random_small(bench: &mut Bencher) {
             /* Exponentially distributed random numbers from the range 0..256.  */
             let numbers: Vec<$t> = (0..256)
                 .map(|_| {
-                    let x = (rng.gen::<u8>() >> rng.gen_range(0u8::BITS)) as $t;
+                    let x = (rng.gen::<u8>() >> rng.gen_range(0..u8::BITS)) as $t;
                     if x != 0 { x } else { 1 }
                 })
                 .collect();
index 1a379ecc11c01d7ae8cdfde75d8a591425eaa2ca..9ca4947ed8f8bb7978870a8a6c01880f7b1d8bdc 100644 (file)
 //! ```
 //!
 //! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then
-//! the `get_context_ref` call will return a reference to `obj.some_string` with type `&String`.
+//! the `get_context_by_ref` call will return a reference to `obj.some_string` with type `&String`.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index b4e173ce03d8a6b5ca911005712ab8daf4d217da..129213fde7491c8ef02040003c6dc7314af694de 100644 (file)
@@ -807,7 +807,8 @@ pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
     ///
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently borrowed, or
+    /// if `self` and `other` point to the same `RefCell`.
     ///
     /// # Examples
     ///
@@ -1193,7 +1194,7 @@ fn default() -> RefCell<T> {
 impl<T: ?Sized + PartialEq> PartialEq for RefCell<T> {
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn eq(&self, other: &RefCell<T>) -> bool {
         *self.borrow() == *other.borrow()
@@ -1207,7 +1208,7 @@ impl<T: ?Sized + Eq> Eq for RefCell<T> {}
 impl<T: ?Sized + PartialOrd> PartialOrd for RefCell<T> {
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn partial_cmp(&self, other: &RefCell<T>) -> Option<Ordering> {
         self.borrow().partial_cmp(&*other.borrow())
@@ -1215,7 +1216,7 @@ fn partial_cmp(&self, other: &RefCell<T>) -> Option<Ordering> {
 
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn lt(&self, other: &RefCell<T>) -> bool {
         *self.borrow() < *other.borrow()
@@ -1223,7 +1224,7 @@ fn lt(&self, other: &RefCell<T>) -> bool {
 
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn le(&self, other: &RefCell<T>) -> bool {
         *self.borrow() <= *other.borrow()
@@ -1231,7 +1232,7 @@ fn le(&self, other: &RefCell<T>) -> bool {
 
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn gt(&self, other: &RefCell<T>) -> bool {
         *self.borrow() > *other.borrow()
@@ -1239,7 +1240,7 @@ fn gt(&self, other: &RefCell<T>) -> bool {
 
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn ge(&self, other: &RefCell<T>) -> bool {
         *self.borrow() >= *other.borrow()
@@ -1250,7 +1251,7 @@ fn ge(&self, other: &RefCell<T>) -> bool {
 impl<T: ?Sized + Ord> Ord for RefCell<T> {
     /// # Panics
     ///
-    /// Panics if the value in either `RefCell` is currently borrowed.
+    /// Panics if the value in either `RefCell` is currently mutably borrowed.
     #[inline]
     fn cmp(&self, other: &RefCell<T>) -> Ordering {
         self.borrow().cmp(&*other.borrow())
@@ -1783,7 +1784,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// until the reference expires. As a special exception, given an `&T`, any part of it that is
 /// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the
 /// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part
-/// of what a reference points to, this means the memory an `&T` points to can be deallocted only if
+/// of what a reference points to, this means the memory an `&T` points to can be deallocated only if
 /// *every part of it* (including padding) is inside an `UnsafeCell`.
 ///
 ///     However, whenever a `&UnsafeCell<T>` is constructed or dereferenced, it must still point to
@@ -1993,7 +1994,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
     pub const fn get(&self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
-        // #[repr(transparent)]. This exploits libstd's special status, there is
+        // #[repr(transparent)]. This exploits std's special status, there is
         // no guarantee for user code that this will work in future versions of the compiler!
         self as *const UnsafeCell<T> as *const T as *mut T
     }
@@ -2051,7 +2052,7 @@ pub const fn get_mut(&mut self) -> &mut T {
     #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
     pub const fn raw_get(this: *const Self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
-        // #[repr(transparent)]. This exploits libstd's special status, there is
+        // #[repr(transparent)]. This exploits std's special status, there is
         // no guarantee for user code that this will work in future versions of the compiler!
         this as *const T as *mut T
     }
index b355d94ce4976697ff0226398b040c248f97ee38..65d12c25c51a48a13c7ddb7de65e233447764827 100644 (file)
@@ -35,7 +35,7 @@ pub struct LazyCell<T, F = fn() -> T> {
     init: Cell<Option<F>>,
 }
 
-impl<T, F> LazyCell<T, F> {
+impl<T, F: FnOnce() -> T> LazyCell<T, F> {
     /// Creates a new lazy value with the given initializing function.
     ///
     /// # Examples
@@ -51,13 +51,12 @@ impl<T, F> LazyCell<T, F> {
     ///
     /// assert_eq!(&*lazy, "HELLO, WORLD!");
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub const fn new(init: F) -> LazyCell<T, F> {
         LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) }
     }
-}
 
-impl<T, F: FnOnce() -> T> LazyCell<T, F> {
     /// Forces the evaluation of this lazy value and returns a reference to
     /// the result.
     ///
@@ -75,6 +74,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
     /// assert_eq!(LazyCell::force(&lazy), &92);
     /// assert_eq!(&*lazy, &92);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn force(this: &LazyCell<T, F>) -> &T {
         this.cell.get_or_init(|| match this.init.take() {
@@ -87,6 +87,7 @@ pub fn force(this: &LazyCell<T, F>) -> &T {
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
     type Target = T;
+    #[inline]
     fn deref(&self) -> &T {
         LazyCell::force(self)
     }
@@ -95,6 +96,7 @@ fn deref(&self) -> &T {
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: Default> Default for LazyCell<T> {
     /// Creates a new lazy value using `Default` as the initializing function.
+    #[inline]
     fn default() -> LazyCell<T> {
         LazyCell::new(T::default)
     }
index 8c01643c7ac177a4d0e5027536b605a74e699278..7757068a4f2b97cbdbf606c90078e1d0fc3925ff 100644 (file)
@@ -37,8 +37,9 @@ pub struct OnceCell<T> {
 
 impl<T> OnceCell<T> {
     /// Creates a new empty cell.
-    #[unstable(feature = "once_cell", issue = "74465")]
+    #[inline]
     #[must_use]
+    #[unstable(feature = "once_cell", issue = "74465")]
     pub const fn new() -> OnceCell<T> {
         OnceCell { inner: UnsafeCell::new(None) }
     }
@@ -46,6 +47,7 @@ pub const fn new() -> OnceCell<T> {
     /// Gets the reference to the underlying value.
     ///
     /// Returns `None` if the cell is empty.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get(&self) -> Option<&T> {
         // SAFETY: Safe due to `inner`'s invariant
@@ -55,6 +57,7 @@ pub fn get(&self) -> Option<&T> {
     /// Gets the mutable reference to the underlying value.
     ///
     /// Returns `None` if the cell is empty.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_mut(&mut self) -> Option<&mut T> {
         self.inner.get_mut().as_mut()
@@ -82,6 +85,7 @@ pub fn get_mut(&mut self) -> Option<&mut T> {
     ///
     /// assert!(cell.get().is_some());
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn set(&self, value: T) -> Result<(), T> {
         // SAFETY: Safe because we cannot have overlapping mutable borrows
@@ -123,6 +127,7 @@ pub fn set(&self, value: T) -> Result<(), T> {
     /// let value = cell.get_or_init(|| unreachable!());
     /// assert_eq!(value, &92);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_or_init<F>(&self, f: F) -> &T
     where
@@ -205,6 +210,7 @@ fn outlined_call<F, T, E>(f: F) -> Result<T, E>
     /// cell.set("hello".to_string()).unwrap();
     /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn into_inner(self) -> Option<T> {
         // Because `into_inner` takes `self` by value, the compiler statically verifies
@@ -233,6 +239,7 @@ pub fn into_inner(self) -> Option<T> {
     /// assert_eq!(cell.take(), Some("hello".to_string()));
     /// assert_eq!(cell.get(), None);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn take(&mut self) -> Option<T> {
         mem::take(self).into_inner()
@@ -241,6 +248,7 @@ pub fn take(&mut self) -> Option<T> {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T> Default for OnceCell<T> {
+    #[inline]
     fn default() -> Self {
         Self::new()
     }
@@ -258,6 +266,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: Clone> Clone for OnceCell<T> {
+    #[inline]
     fn clone(&self) -> OnceCell<T> {
         let res = OnceCell::new();
         if let Some(value) = self.get() {
@@ -272,6 +281,7 @@ fn clone(&self) -> OnceCell<T> {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: PartialEq> PartialEq for OnceCell<T> {
+    #[inline]
     fn eq(&self, other: &Self) -> bool {
         self.get() == other.get()
     }
@@ -283,6 +293,7 @@ impl<T: Eq> Eq for OnceCell<T> {}
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T> const From<T> for OnceCell<T> {
     /// Creates a new `OnceCell<T>` which already contains the given `value`.
+    #[inline]
     fn from(value: T) -> Self {
         OnceCell { inner: UnsafeCell::new(Some(value)) }
     }
index c05b68e30bc90c88d2f78746ab8e99e0d9b44563..3e7383b4cd199fa5996a6429a2151819d5a5b55b 100644 (file)
@@ -140,7 +140,7 @@ pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::Into
     /// assert_eq!(None, c);
     /// ```
     #[stable(feature = "assoc_char_funcs", since = "1.52.0")]
-    #[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
     #[must_use]
     #[inline]
     pub const fn from_u32(i: u32) -> Option<char> {
@@ -241,7 +241,7 @@ pub const fn from_u32(i: u32) -> Option<char> {
     /// let _c = char::from_digit(1, 37);
     /// ```
     #[stable(feature = "assoc_char_funcs", since = "1.52.0")]
-    #[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
     #[must_use]
     #[inline]
     pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
@@ -338,7 +338,7 @@ pub fn is_digit(self, radix: u32) -> bool {
     /// let _ = '1'.to_digit(37);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
     #[inline]
index 55552376280ab045a5ecbf0bfa64c3a72b298aae..af98059cf42c3e36d882e031ed7a2bd770a10c9f 100644 (file)
@@ -110,7 +110,7 @@ pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::Into
 
 /// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
 #[must_use]
 #[inline]
 pub const fn from_u32(i: u32) -> Option<char> {
@@ -130,7 +130,7 @@ pub const fn from_u32(i: u32) -> Option<char> {
 
 /// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_char_convert", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
 #[must_use]
 #[inline]
 pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
index 949896e57480677b8192509782d00380558c9ed9..ebf5baa3c020bf898a68c25094675f4f0422e81d 100644 (file)
@@ -24,8 +24,6 @@
 
 use crate::const_closure::ConstFnMutClosure;
 use crate::marker::Destruct;
-#[cfg(bootstrap)]
-use crate::marker::StructuralPartialEq;
 
 use self::Ordering::*;
 
@@ -333,7 +331,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
 /// assert_eq!(Ordering::Greater, result);
 /// ```
 #[derive(Clone, Copy, Eq, Debug, Hash)]
-#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq))]
+#[derive_const(PartialOrd, Ord, PartialEq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(i8)]
 pub enum Ordering {
@@ -800,9 +798,12 @@ fn max(self, other: Self) -> Self
         Self: Sized,
         Self: ~const Destruct,
     {
-        // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)`
-        // when trait methods are allowed to be used when a const closure is
-        // expected.
+        #[cfg(not(bootstrap))]
+        {
+            max_by(self, other, Ord::cmp)
+        }
+
+        #[cfg(bootstrap)]
         match self.cmp(&other) {
             Ordering::Less | Ordering::Equal => other,
             Ordering::Greater => self,
@@ -827,9 +828,12 @@ fn min(self, other: Self) -> Self
         Self: Sized,
         Self: ~const Destruct,
     {
-        // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)`
-        // when trait methods are allowed to be used when a const closure is
-        // expected.
+        #[cfg(not(bootstrap))]
+        {
+            min_by(self, other, Ord::cmp)
+        }
+
+        #[cfg(bootstrap)]
         match self.cmp(&other) {
             Ordering::Less | Ordering::Equal => self,
             Ordering::Greater => other,
@@ -879,40 +883,6 @@ fn clamp(self, min: Self, max: Self) -> Self
     /* compiler built-in */
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(bootstrap)]
-impl StructuralPartialEq for Ordering {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-#[cfg(bootstrap)]
-impl const PartialEq for Ordering {
-    #[inline]
-    fn eq(&self, other: &Self) -> bool {
-        (*self as i32).eq(&(*other as i32))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-#[cfg(bootstrap)]
-impl const Ord for Ordering {
-    #[inline]
-    fn cmp(&self, other: &Ordering) -> Ordering {
-        (*self as i32).cmp(&(*other as i32))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-#[cfg(bootstrap)]
-impl const PartialOrd for Ordering {
-    #[inline]
-    fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
-        (*self as i32).partial_cmp(&(*other as i32))
-    }
-}
-
 /// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
 ///
 /// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
index 920c31233c18799a254a9f82282f8dbc30a56371..97900a4862f5653fc49c537fdc95c3690d71d9a0 100644 (file)
@@ -1,5 +1,4 @@
 use crate::marker::Destruct;
-#[cfg(not(bootstrap))]
 use crate::marker::Tuple;
 
 /// Struct representing a closure with mutably borrowed data.
@@ -46,33 +45,6 @@ pub(crate) const fn new<ClosureArguments, ClosureReturnValue>(
 
 macro_rules! impl_fn_mut_tuple {
     ($($var:ident)*) => {
-        #[cfg(bootstrap)]
-        #[allow(unused_parens)]
-        impl<'a, $($var,)* ClosureArguments, 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)
-            }
-        }
-        #[cfg(bootstrap)]
-        #[allow(unused_parens)]
-        impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
-            FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
-        where
-            Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue + ~const Destruct,
-        {
-            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)
-            }
-        }
-        #[cfg(not(bootstrap))]
         #[allow(unused_parens)]
         impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
             FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
@@ -85,7 +57,6 @@ extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Outpu
             self.call_mut(args)
             }
         }
-        #[cfg(not(bootstrap))]
         #[allow(unused_parens)]
         impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
             FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
index 5f4a666de928439750910fc044105108d7c7a612..51e6a76cea848c540ac8a6beda22fa434c7a6e88 100644 (file)
@@ -558,7 +558,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 ///
 /// Derived `Debug` formats are not stable, and so may change with future Rust
 /// versions. Additionally, `Debug` implementations of types provided by the
-/// standard library (`libstd`, `libcore`, `liballoc`, etc.) are not stable, and
+/// standard library (`std`, `core`, `alloc`, etc.) are not stable, and
 /// may also change with future Rust versions.
 ///
 /// # Examples
index f29d3e1e98b724777673fef70d399b4408eb2baa..8c7111cb3ff0b875f22a2369480d03aed05d26ce 100644 (file)
@@ -37,6 +37,7 @@
 pub trait Future {
     /// The type of value produced on completion.
     #[stable(feature = "futures_api", since = "1.36.0")]
+    #[rustc_diagnostic_item = "FutureOutput"]
     type Output;
 
     /// Attempt to resolve the future to a final value, registering
index f2b961d62e00c8149750785c3792cdf94924ce1d..5bfe001de46e3775f456a9c42c026b0b4230e253 100644 (file)
@@ -44,7 +44,7 @@
 ///    non-Send/Sync as well, and we don't want that.
 ///
 /// It also simplifies the HIR lowering of `.await`.
-#[cfg_attr(not(bootstrap), lang = "ResumeTy")]
+#[lang = "ResumeTy"]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[derive(Debug, Copy, Clone)]
@@ -61,7 +61,6 @@ unsafe impl Sync for ResumeTy {}
 /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
 /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
 // This is `const` to avoid extra errors after we recover from `const async fn`
-#[cfg_attr(bootstrap, lang = "from_generator")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[rustc_const_unstable(feature = "gen_future", issue = "50547")]
@@ -113,10 +112,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
     unsafe { &mut *cx.0.as_ptr().cast() }
 }
 
-#[cfg_attr(not(bootstrap), lang = "identity_future")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[inline]
+#[lang = "identity_future"]
 pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
     f
 }
index 6eeaef5ab0129d195f09aba1d025b90190ef7922..a315a28fb0d943f24deb882e1cdf8937637c5315 100644 (file)
@@ -55,7 +55,6 @@
 #![allow(missing_docs)]
 
 use crate::marker::DiscriminantKind;
-#[cfg(not(bootstrap))]
 use crate::marker::Tuple;
 use crate::mem;
 
@@ -2175,66 +2174,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
     /// which violates the principle that a `const fn` must behave the same at
     /// compile-time and at run-time. The unsafe code in crate B is fine.
-    #[cfg(bootstrap)]
-    #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
-    pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
-    where
-        G: FnOnce<ARG, Output = RET>,
-        F: FnOnce<ARG, Output = RET>;
-
-    /// Selects which function to call depending on the context.
-    ///
-    /// If this function is evaluated at compile-time, then a call to this
-    /// intrinsic will be replaced with a call to `called_in_const`. It gets
-    /// replaced with a call to `called_at_rt` otherwise.
-    ///
-    /// # Type Requirements
-    ///
-    /// The two functions must be both function items. They cannot be function
-    /// pointers or closures. The first function must be a `const fn`.
-    ///
-    /// `arg` will be the tupled arguments that will be passed to either one of
-    /// the two functions, therefore, both functions must accept the same type of
-    /// arguments. Both functions must return RET.
-    ///
-    /// # Safety
-    ///
-    /// The two functions must behave observably equivalent. Safe code in other
-    /// crates may assume that calling a `const fn` at compile-time and at run-time
-    /// produces the same result. A function that produces a different result when
-    /// evaluated at run-time, or has any other observable side-effects, is
-    /// *unsound*.
-    ///
-    /// Here is an example of how this could cause a problem:
-    /// ```no_run
-    /// #![feature(const_eval_select)]
-    /// #![feature(core_intrinsics)]
-    /// use std::hint::unreachable_unchecked;
-    /// use std::intrinsics::const_eval_select;
-    ///
-    /// // Crate A
-    /// pub const fn inconsistent() -> i32 {
-    ///     fn runtime() -> i32 { 1 }
-    ///     const fn compiletime() -> i32 { 2 }
-    ///
-    ///     unsafe {
-    //          // ⚠ This code violates the required equivalence of `compiletime`
-    ///         // and `runtime`.
-    ///         const_eval_select((), compiletime, runtime)
-    ///     }
-    /// }
-    ///
-    /// // Crate B
-    /// const X: i32 = inconsistent();
-    /// let x = inconsistent();
-    /// if x != X { unsafe { unreachable_unchecked(); }}
-    /// ```
-    ///
-    /// This code causes Undefined Behavior when being run, since the
-    /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
-    /// which violates the principle that a `const fn` must behave the same at
-    /// compile-time and at run-time. The unsafe code in crate B is fine.
-    #[cfg(not(bootstrap))]
     #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
     pub fn const_eval_select<ARG: Tuple, F, G, RET>(
         arg: ARG,
index 9e7099ddfd1e1d98756d5b7624e0da4e20eca346..399d54f18c5b3803b7b4d3fc69da33dccbf8e692 100644 (file)
@@ -60,7 +60,8 @@
 //!
 //! # Examples
 //!
-//! ```rust
+#![cfg_attr(bootstrap, doc = "```rust,compile_fail")]
+#![cfg_attr(not(bootstrap), doc = "```rust")]
 //! #![feature(core_intrinsics, custom_mir)]
 //!
 //! extern crate core;
@@ -291,7 +292,8 @@ fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discrim
     ///
     /// # Examples
     ///
-    /// ```rust
+    #[cfg_attr(bootstrap, doc = "```rust,compile_fail")]
+    #[cfg_attr(not(bootstrap), doc = "```rust")]
     /// #![feature(custom_mir, core_intrinsics)]
     ///
     /// extern crate core;
index 98734c527f2b9c35874027386cb9c1008276a7e3..617dfd12383fb649e9e76ab8f9fed16e06ecec6b 100644 (file)
@@ -22,17 +22,12 @@ pub const fn empty<T>() -> Empty<T> {
     Empty(marker::PhantomData)
 }
 
-// Newtype for use in `PhantomData` to avoid
-// > error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-// in `const fn empty<T>()` above.
-struct FnReturning<T>(fn() -> T);
-
 /// An iterator that yields nothing.
 ///
 /// This `struct` is created by the [`empty()`] function. See its documentation for more.
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "iter_empty", since = "1.2.0")]
-pub struct Empty<T>(marker::PhantomData<FnReturning<T>>);
+pub struct Empty<T>(marker::PhantomData<fn() -> T>);
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
 impl<T> fmt::Debug for Empty<T> {
index d79f85c2559fedf5f3e2f0641f8ca69a71c57edd..080ae27a30fcf976dd3e483e8fe6b14d8f3f65e4 100644 (file)
@@ -1,3 +1,4 @@
+use crate::fmt;
 use crate::iter::{FusedIterator, TrustedLen};
 
 /// Creates an iterator that lazily generates a value exactly once by invoking
@@ -66,12 +67,23 @@ pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
 ///
 /// This `struct` is created by the [`once_with()`] function.
 /// See its documentation for more.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 #[stable(feature = "iter_once_with", since = "1.43.0")]
 pub struct OnceWith<F> {
     gen: Option<F>,
 }
 
+#[stable(feature = "iter_once_with_debug", since = "CURRENT_RUSTC_VERSION")]
+impl<F> fmt::Debug for OnceWith<F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.gen.is_some() {
+            f.write_str("OnceWith(Some(_))")
+        } else {
+            f.write_str("OnceWith(None)")
+        }
+    }
+}
+
 #[stable(feature = "iter_once_with", since = "1.43.0")]
 impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
     type Item = A;
index fd8d25ce1a55e3b2280652cbf9bf2ac593edf4fd..dc61d6065b8edaae5c11cc055aedc98c3ef7be36 100644 (file)
@@ -126,7 +126,7 @@ fn next(&mut self) -> Option<A> {
             // zero so it won't be dropped later, and thus it's okay to take it here.
             unsafe { ManuallyDrop::take(&mut self.element) }
         } else {
-            A::clone(&mut self.element)
+            A::clone(&self.element)
         })
     }
 
index ab2d0472b4701c205e0426582b5587c42baabeb9..20420a3ad8e02a83df814e758b5cc9e8481f83a2 100644 (file)
@@ -1,3 +1,4 @@
+use crate::fmt;
 use crate::iter::{FusedIterator, TrustedLen};
 use crate::ops::Try;
 
@@ -71,12 +72,19 @@ pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
 ///
 /// This `struct` is created by the [`repeat_with()`] function.
 /// See its documentation for more.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
 #[stable(feature = "iterator_repeat_with", since = "1.28.0")]
 pub struct RepeatWith<F> {
     repeater: F,
 }
 
+#[stable(feature = "iterator_repeat_with_debug", since = "CURRENT_RUSTC_VERSION")]
+impl<F> fmt::Debug for RepeatWith<F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("RepeatWith").finish_non_exhaustive()
+    }
+}
+
 #[stable(feature = "iterator_repeat_with", since = "1.28.0")]
 impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
     type Item = A;
index bac836292f8fa836c163823280463423b12b6700..99aaf798e411fb01dbea3c1c5b0286e014fe03d2 100644 (file)
@@ -66,6 +66,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub trait Iterator {
     /// The type of the elements being iterated over.
+    #[rustc_diagnostic_item = "IteratorItem"]
     #[stable(feature = "rust1", since = "1.0.0")]
     type Item;
 
@@ -803,7 +804,7 @@ fn map<B, F>(self, f: F) -> Map<Self, F>
     /// (0..5).map(|x| x * 2 + 1)
     ///       .for_each(move |x| tx.send(x).unwrap());
     ///
-    /// let v: Vec<_> =  rx.iter().collect();
+    /// let v: Vec<_> = rx.iter().collect();
     /// assert_eq!(v, vec![1, 3, 5, 7, 9]);
     /// ```
     ///
@@ -1380,8 +1381,8 @@ fn take(self, n: usize) -> Take<Self>
         Take::new(self, n)
     }
 
-    /// An iterator adapter similar to [`fold`] that holds internal state and
-    /// produces a new iterator.
+    /// An iterator adapter which, like [`fold`], holds internal state, but
+    /// unlike [`fold`], produces a new iterator.
     ///
     /// [`fold`]: Iterator::fold
     ///
@@ -1393,20 +1394,25 @@ fn take(self, n: usize) -> Take<Self>
     ///
     /// On iteration, the closure will be applied to each element of the
     /// iterator and the return value from the closure, an [`Option`], is
-    /// yielded by the iterator.
+    /// returned by the `next` method. Thus the closure can return
+    /// `Some(value)` to yield `value`, or `None` to end the iteration.
     ///
     /// # Examples
     ///
     /// Basic usage:
     ///
     /// ```
-    /// let a = [1, 2, 3];
+    /// let a = [1, 2, 3, 4];
     ///
     /// let mut iter = a.iter().scan(1, |state, &x| {
-    ///     // each iteration, we'll multiply the state by the element
+    ///     // each iteration, we'll multiply the state by the element ...
     ///     *state = *state * x;
     ///
-    ///     // then, we'll yield the negation of the state
+    ///     // ... and terminate if the state exceeds 6
+    ///     if *state > 6 {
+    ///         return None;
+    ///     }
+    ///     // ... else yield the negation of the state
     ///     Some(-*state)
     /// });
     ///
@@ -1508,6 +1514,18 @@ fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
     /// assert_eq!(merged, "alphabetagamma");
     /// ```
     ///
+    /// Flattening works on any `IntoIterator` type, including `Option` and `Result`:
+    ///
+    /// ```
+    /// let options = vec![Some(123), Some(321), None, Some(231)];
+    /// let flattened_options: Vec<_> = options.into_iter().flatten().collect();
+    /// assert_eq!(flattened_options, vec![123, 321, 231]);
+    ///
+    /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)];
+    /// let flattened_results: Vec<_> = results.into_iter().flatten().collect();
+    /// assert_eq!(flattened_results, vec![123, 321, 231]);
+    /// ```
+    ///
     /// Flattening only removes one level of nesting at a time:
     ///
     /// ```
@@ -2653,7 +2671,10 @@ fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()
     /// argument is a double reference. You can see this effect in the
     /// examples below, with `&&x`.
     ///
+    /// If you need the index of the element, see [`position()`].
+    ///
     /// [`Some(element)`]: Some
+    /// [`position()`]: Iterator::position
     ///
     /// # Examples
     ///
index 1823fd3006279d1c7bacddb75892b04b3fd93204..9e0d7cab63e5c1d3efc36e508955cc9b8eb3dd89 100644 (file)
 //!    which do not trigger a panic can be assured that this function is never
 //!    called. The `lang` attribute is called `eh_personality`.
 
-// Since libcore defines many fundamental lang items, all tests live in a
-// separate crate, libcoretest, to avoid bizarre issues.
+// Since core defines many fundamental lang items, all tests live in a
+// separate crate, libcoretest (library/core/tests), to avoid bizarre issues.
 //
 // Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
 // this, both the generated test artifact and the linked libtest (which
-// transitively includes libcore) will both define the same set of lang items,
+// transitively includes core) will both define the same set of lang items,
 // and this will cause the E0152 "found duplicate lang item" error. See
 // discussion in #50466 for details.
 //
 // This cfg won't affect doc tests.
 #![cfg(not(test))]
-// To run libcore tests without x.py without ending up with two copies of libcore, Miri needs to be
+// To run core tests without x.py without ending up with two copies of core, Miri needs to be
 // able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
 // rustc itself never sets the feature, so this line has no affect there.
 #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
 #![feature(const_unsafecell_get_mut)]
 #![feature(const_waker)]
 #![feature(core_panic)]
+#![feature(char_indices_offset)]
 #![feature(duration_consts_float)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(ptr_alignment_type)]
 #![feature(slice_ptr_get)]
 #![feature(slice_split_at_unchecked)]
 #![feature(str_internals)]
+#![feature(str_split_remainder)]
+#![feature(str_split_inclusive_remainder)]
 #![feature(strict_provenance)]
 #![feature(utf16_extra)]
 #![feature(utf16_extra_const)]
 #![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
-#![cfg_attr(not(bootstrap), feature(derive_const))]
+#![feature(derive_const)]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
 #![feature(rustdoc_internals)]
@@ -309,7 +312,7 @@ pub mod assert_matches {
 #[macro_use]
 pub mod num;
 
-/* The libcore prelude, not as all-encompassing as the libstd prelude */
+/* The core prelude, not as all-encompassing as the std prelude */
 
 pub mod prelude;
 
@@ -376,12 +379,12 @@ pub mod assert_matches {
 #[stable(feature = "core_primitive", since = "1.43.0")]
 pub mod primitive;
 
-// Pull in the `core_arch` crate directly into libcore. The contents of
+// Pull in the `core_arch` crate directly into core. The contents of
 // `core_arch` are in a different repository: rust-lang/stdarch.
 //
-// `core_arch` depends on libcore, but the contents of this module are
+// `core_arch` depends on core, but the contents of this module are
 // set up in such a way that directly pulling it here works such that the
-// crate uses the this crate as its libcore.
+// crate uses the this crate as its core.
 #[path = "../../stdarch/crates/core_arch/src/mod.rs"]
 #[allow(
     missing_docs,
@@ -400,12 +403,12 @@ pub mod assert_matches {
 #[stable(feature = "simd_arch", since = "1.27.0")]
 pub mod arch;
 
-// Pull in the `core_simd` crate directly into libcore. The contents of
+// Pull in the `core_simd` crate directly into core. The contents of
 // `core_simd` are in a different repository: rust-lang/portable-simd.
 //
-// `core_simd` depends on libcore, but the contents of this module are
+// `core_simd` depends on core, but the contents of this module are
 // set up in such a way that directly pulling it here works such that the
-// crate uses this crate as its libcore.
+// crate uses this crate as its core.
 #[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
 #[allow(rustdoc::bare_urls)]
index f29cd357d6bfd5218ab7489a3d40148b184d8231..3b026bc0e0f381bd23b847f3c9ecd0fcf0ca315b 100644 (file)
@@ -1315,22 +1315,41 @@ macro_rules! cfg {
 
     /// Parses a file as an expression or an item according to the context.
     ///
-    /// The file is located relative to the current file (similarly to how
-    /// modules are found). The provided path is interpreted in a platform-specific
-    /// way at compile time. So, for instance, an invocation with a Windows path
-    /// containing backslashes `\` would not compile correctly on Unix.
+    /// **Warning**: For multi-file Rust projects, the `include!` macro is probably not what you
+    /// are looking for. Usually, multi-file Rust projects use
+    /// [modules](https://doc.rust-lang.org/reference/items/modules.html). Multi-file projects and
+    /// modules are explained in the Rust-by-Example book
+    /// [here](https://doc.rust-lang.org/rust-by-example/mod/split.html) and the module system is
+    /// explained in the Rust Book
+    /// [here](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html).
+    ///
+    /// The included file is placed in the surrounding code
+    /// [unhygienically](https://doc.rust-lang.org/reference/macros-by-example.html#hygiene). If
+    /// the included file is parsed as an expression and variables or functions share names across
+    /// both files, it could result in variables or functions being different from what the
+    /// included file expected.
+    ///
+    /// The included file is located relative to the current file (similarly to how modules are
+    /// found). The provided path is interpreted in a platform-specific way at compile time. So,
+    /// for instance, an invocation with a Windows path containing backslashes `\` would not
+    /// compile correctly on Unix.
     ///
-    /// Using this macro is often a bad idea, because if the file is
-    /// parsed as an expression, it is going to be placed in the
-    /// surrounding code unhygienically. This could result in variables
-    /// or functions being different from what the file expected if
-    /// there are variables or functions that have the same name in
-    /// the current file.
+    /// # Uses
+    ///
+    /// The `include!` macro is primarily used for two purposes. It is used to include
+    /// documentation that is written in a separate file and it is used to include [build artifacts
+    /// usually as a result from the `build.rs`
+    /// script](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script).
+    ///
+    /// When using the `include` macro to include stretches of documentation, remember that the
+    /// included file still needs to be a valid rust syntax. It is also possible to
+    /// use the [`include_str`] macro as `#![doc = include_str!("...")]` (at the module level) or
+    /// `#[doc = include_str!("...")]` (at the item level) to include documentation from a plain
+    /// text or markdown file.
     ///
     /// # Examples
     ///
-    /// Assume there are two files in the same directory with the following
-    /// contents:
+    /// Assume there are two files in the same directory with the following contents:
     ///
     /// File 'monkeys.in':
     ///
@@ -1461,7 +1480,6 @@ macro_rules! trace_macros {
     /// [the reference]: ../../../reference/attributes/derive.html
     #[unstable(feature = "derive_const", issue = "none")]
     #[rustc_builtin_macro]
-    #[cfg(not(bootstrap))]
     pub macro derive_const($item:item) {
         /* compiler built-in */
     }
@@ -1516,7 +1534,6 @@ macro_rules! trace_macros {
     /// Attribute macro applied to a function to register it as a handler for allocation failure.
     ///
     /// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "alloc_error_handler", issue = "51540")]
     #[allow_internal_unstable(rustc_attrs)]
     #[rustc_builtin_macro]
@@ -1553,7 +1570,6 @@ macro_rules! trace_macros {
         issue = "23416",
         reason = "placeholder syntax for type ascription"
     )]
-    #[cfg(not(bootstrap))]
     pub macro type_ascribe($expr:expr, $ty:ty) {
         /* compiler built-in */
     }
index 4b85c1112b94096b8132b7607fc4c05368ff7196..1326fc9ab096f03d6edde634db009dc697c17c15 100644 (file)
@@ -96,7 +96,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
 )]
 #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
 #[rustc_specialization_trait]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
 pub trait Sized {
     // Empty.
 }
@@ -128,7 +128,7 @@ pub trait Sized {
 /// [nomicon-coerce]: ../../nomicon/coercions.html
 #[unstable(feature = "unsize", issue = "18598")]
 #[lang = "unsize"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
 pub trait Unsize<T: ?Sized> {
     // Empty.
 }
@@ -623,6 +623,12 @@ impl<T: ?Sized> !Sync for *mut T {}
 /// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
 /// as not to indicate ownership.
 ///
+/// ## Layout
+///
+/// For all `T`, the following are guaranteed:
+/// * `size_of::<PhantomData<T>>() == 0`
+/// * `align_of::<PhantomData<T>>() == 1`
+///
 /// [drop check]: ../../nomicon/dropck.html
 #[lang = "phantom_data"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -695,7 +701,7 @@ impl<T: ?Sized> StructuralEq for PhantomData<T> {}
     reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
 )]
 #[lang = "discriminant_kind"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
 pub trait DiscriminantKind {
     /// The type of the discriminant, which must satisfy the trait
     /// bounds required by `mem::Discriminant`.
@@ -796,7 +802,7 @@ impl<T: ?Sized> Unpin for *mut T {}
 #[lang = "destruct"]
 #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
 #[const_trait]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
 pub trait Destruct {}
 
 /// A marker for tuple types.
@@ -806,12 +812,12 @@ pub trait Destruct {}
 #[unstable(feature = "tuple_trait", issue = "none")]
 #[lang = "tuple_trait"]
 #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
 pub trait Tuple {}
 
 /// A marker for things
 #[unstable(feature = "pointer_sized_trait", issue = "none")]
-#[cfg_attr(not(bootstrap), lang = "pointer_sized")]
+#[lang = "pointer_sized"]
 #[rustc_on_unimplemented(
     message = "`{Self}` needs to be a pointer-sized type",
     label = "`{Self}` needs to be a pointer-sized type"
index 2c6a0ba64f266ea5f4165a4040e9d80039173d06..1308b0770b848a80aed914166b90616241f09b29 100644 (file)
@@ -428,7 +428,7 @@ pub const fn is_nan(self) -> bool {
         self != self
     }
 
-    // FIXME(#50145): `abs` is publicly unavailable in libcore due to
+    // FIXME(#50145): `abs` is publicly unavailable in core due to
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
index fd3c18ce29bd289c3822937e7e4c23b54dc661ad..2a22c4302b91bd97ecb97c823b6de0a51bc48508 100644 (file)
@@ -427,7 +427,7 @@ pub const fn is_nan(self) -> bool {
         self != self
     }
 
-    // FIXME(#50145): `abs` is publicly unavailable in libcore due to
+    // FIXME(#50145): `abs` is publicly unavailable in core due to
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
index e1ab7ac5ff045e056a2ba2c26a295867e7137042..57096f4397436359d84f12b354598eb7f673f48c 100644 (file)
@@ -2290,8 +2290,8 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         /// ```
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
@@ -2313,8 +2313,8 @@ pub const fn ilog(self, base: Self) -> u32 {
         /// ```
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
@@ -2335,8 +2335,8 @@ pub const fn ilog2(self) -> u32 {
         /// ```
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
@@ -2360,8 +2360,8 @@ pub const fn ilog10(self) -> u32 {
         /// ```
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2396,8 +2396,8 @@ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
         /// ```
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2420,8 +2420,8 @@ pub const fn checked_ilog2(self) -> Option<u32> {
         /// ```
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index 6a339b338d990f87c410fd146eebdb29d59b9616..fbda8f82b1bd906726775816fc920de7abb30c4b 100644 (file)
@@ -462,8 +462,8 @@ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
                 /// ```
-                #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-                #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+                #[stable(feature = "int_log", since = "1.67.0")]
+                #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -486,8 +486,8 @@ pub const fn ilog2(self) -> u32 {
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
                 /// ```
-                #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-                #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+                #[stable(feature = "int_log", since = "1.67.0")]
+                #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -1253,7 +1253,7 @@ impl $Ty {
                 ///
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")]
                 /// ```
-                #[stable(feature = "nonzero_bits", since = "CURRENT_RUSTC_VERSION")]
+                #[stable(feature = "nonzero_bits", since = "1.67.0")]
                 pub const BITS: u32 = <$Int>::BITS;
             }
         )+
index af74faa90b11031c954536972b8ab5e9170a0e25..1c97c46862833a2e2c351c69649f782ac18a6b97 100644 (file)
@@ -703,8 +703,8 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
         /// ```
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
@@ -726,8 +726,8 @@ pub const fn ilog(self, base: Self) -> u32 {
         /// ```
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
@@ -748,8 +748,8 @@ pub const fn ilog2(self) -> u32 {
         /// ```
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[rustc_allow_const_fn_unstable(const_option)]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
@@ -773,8 +773,8 @@ pub const fn ilog10(self) -> u32 {
         /// ```
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -809,8 +809,8 @@ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
         /// ```
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -831,8 +831,8 @@ pub const fn checked_ilog2(self) -> Option<u32> {
         /// ```
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
-        #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
-        #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+        #[stable(feature = "int_log", since = "1.67.0")]
+        #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index 127b047db9192510521f49fe0279cabe79a918c8..b7e1aee9d84d123be63137e0ea81b026e7d855c7 100644 (file)
@@ -1,4 +1,3 @@
-#[cfg(not(bootstrap))]
 use crate::marker::Tuple;
 
 /// The version of the call operator that takes an immutable receiver.
 /// let double = |x| x * 2;
 /// assert_eq!(call_with_one(double), 2);
 /// ```
-#[cfg(bootstrap)]
-#[lang = "fn"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_paren_sugar]
-#[rustc_on_unimplemented(
-    on(
-        Args = "()",
-        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
-    ),
-    on(
-        _Self = "unsafe fn",
-        note = "unsafe function cannot be called generically without an unsafe block",
-        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
-        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
-    ),
-    message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
-    label = "expected an `Fn<{Args}>` closure, found `{Self}`"
-)]
-#[fundamental] // so that regex can rely that `&str: !FnMut`
-#[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
-pub trait Fn<Args>: FnMut<Args> {
-    /// Performs the call operation.
-    #[unstable(feature = "fn_traits", issue = "29625")]
-    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
-}
-
-/// The version of the call operator that takes an immutable receiver.
-///
-/// Instances of `Fn` can be called repeatedly without mutating state.
-///
-/// *This trait (`Fn`) is not to be confused with [function pointers]
-/// (`fn`).*
-///
-/// `Fn` is implemented automatically by closures which only take immutable
-/// references to captured variables or don't capture anything at all, as well
-/// as (safe) [function pointers] (with some caveats, see their documentation
-/// for more details). Additionally, for any type `F` that implements `Fn`, `&F`
-/// implements `Fn`, too.
-///
-/// Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any
-/// instance of `Fn` can be used as a parameter where a [`FnMut`] or [`FnOnce`]
-/// is expected.
-///
-/// Use `Fn` as a bound when you want to accept a parameter of function-like
-/// type and need to call it repeatedly and without mutating state (e.g., when
-/// calling it concurrently). If you do not need such strict requirements, use
-/// [`FnMut`] or [`FnOnce`] as bounds.
-///
-/// See the [chapter on closures in *The Rust Programming Language*][book] for
-/// some more information on this topic.
-///
-/// Also of note is the special syntax for `Fn` traits (e.g.
-/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
-/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
-///
-/// [book]: ../../book/ch13-01-closures.html
-/// [function pointers]: fn
-/// [nomicon]: ../../nomicon/hrtb.html
-///
-/// # Examples
-///
-/// ## Calling a closure
-///
-/// ```
-/// let square = |x| x * x;
-/// assert_eq!(square(5), 25);
-/// ```
-///
-/// ## Using a `Fn` parameter
-///
-/// ```
-/// fn call_with_one<F>(func: F) -> usize
-///     where F: Fn(usize) -> usize {
-///     func(1)
-/// }
-///
-/// let double = |x| x * 2;
-/// assert_eq!(call_with_one(double), 2);
-/// ```
-#[cfg(not(bootstrap))]
 #[lang = "fn"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
@@ -222,95 +140,6 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
 ///
 /// assert_eq!(x, 5);
 /// ```
-#[cfg(bootstrap)]
-#[lang = "fn_mut"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_paren_sugar]
-#[rustc_on_unimplemented(
-    on(
-        Args = "()",
-        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
-    ),
-    on(
-        _Self = "unsafe fn",
-        note = "unsafe function cannot be called generically without an unsafe block",
-        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
-        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
-    ),
-    message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
-    label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
-)]
-#[fundamental] // so that regex can rely that `&str: !FnMut`
-#[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
-pub trait FnMut<Args>: FnOnce<Args> {
-    /// Performs the call operation.
-    #[unstable(feature = "fn_traits", issue = "29625")]
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-}
-
-/// The version of the call operator that takes a mutable receiver.
-///
-/// Instances of `FnMut` can be called repeatedly and may mutate state.
-///
-/// `FnMut` is implemented automatically by closures which take mutable
-/// references to captured variables, as well as all types that implement
-/// [`Fn`], e.g., (safe) [function pointers] (since `FnMut` is a supertrait of
-/// [`Fn`]). Additionally, for any type `F` that implements `FnMut`, `&mut F`
-/// implements `FnMut`, too.
-///
-/// Since [`FnOnce`] is a supertrait of `FnMut`, any instance of `FnMut` can be
-/// used where a [`FnOnce`] is expected, and since [`Fn`] is a subtrait of
-/// `FnMut`, any instance of [`Fn`] can be used where `FnMut` is expected.
-///
-/// Use `FnMut` as a bound when you want to accept a parameter of function-like
-/// type and need to call it repeatedly, while allowing it to mutate state.
-/// If you don't want the parameter to mutate state, use [`Fn`] as a
-/// bound; if you don't need to call it repeatedly, use [`FnOnce`].
-///
-/// See the [chapter on closures in *The Rust Programming Language*][book] for
-/// some more information on this topic.
-///
-/// Also of note is the special syntax for `Fn` traits (e.g.
-/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
-/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
-///
-/// [book]: ../../book/ch13-01-closures.html
-/// [function pointers]: fn
-/// [nomicon]: ../../nomicon/hrtb.html
-///
-/// # Examples
-///
-/// ## Calling a mutably capturing closure
-///
-/// ```
-/// let mut x = 5;
-/// {
-///     let mut square_x = || x *= x;
-///     square_x();
-/// }
-/// assert_eq!(x, 25);
-/// ```
-///
-/// ## Using a `FnMut` parameter
-///
-/// ```
-/// fn do_twice<F>(mut func: F)
-///     where F: FnMut()
-/// {
-///     func();
-///     func();
-/// }
-///
-/// let mut x: usize = 1;
-/// {
-///     let add_two_to_x = || x += 2;
-///     do_twice(add_two_to_x);
-/// }
-///
-/// assert_eq!(x, 5);
-/// ```
-#[cfg(not(bootstrap))]
 #[lang = "fn_mut"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
@@ -390,92 +219,6 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
 ///
 /// // `consume_and_return_x` can no longer be invoked at this point
 /// ```
-#[cfg(bootstrap)]
-#[lang = "fn_once"]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_paren_sugar]
-#[rustc_on_unimplemented(
-    on(
-        Args = "()",
-        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
-    ),
-    on(
-        _Self = "unsafe fn",
-        note = "unsafe function cannot be called generically without an unsafe block",
-        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
-        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
-    ),
-    message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
-    label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
-)]
-#[fundamental] // so that regex can rely that `&str: !FnMut`
-#[must_use = "closures are lazy and do nothing unless called"]
-#[const_trait]
-pub trait FnOnce<Args> {
-    /// The returned type after the call operator is used.
-    #[lang = "fn_once_output"]
-    #[stable(feature = "fn_once_output", since = "1.12.0")]
-    type Output;
-
-    /// Performs the call operation.
-    #[unstable(feature = "fn_traits", issue = "29625")]
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-/// The version of the call operator that takes a by-value receiver.
-///
-/// Instances of `FnOnce` can be called, but might not be callable multiple
-/// times. Because of this, if the only thing known about a type is that it
-/// implements `FnOnce`, it can only be called once.
-///
-/// `FnOnce` is implemented automatically by closures that might consume captured
-/// variables, as well as all types that implement [`FnMut`], e.g., (safe)
-/// [function pointers] (since `FnOnce` is a supertrait of [`FnMut`]).
-///
-/// Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any instance of
-/// [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected.
-///
-/// Use `FnOnce` as a bound when you want to accept a parameter of function-like
-/// type and only need to call it once. If you need to call the parameter
-/// repeatedly, use [`FnMut`] as a bound; if you also need it to not mutate
-/// state, use [`Fn`].
-///
-/// See the [chapter on closures in *The Rust Programming Language*][book] for
-/// some more information on this topic.
-///
-/// Also of note is the special syntax for `Fn` traits (e.g.
-/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
-/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
-///
-/// [book]: ../../book/ch13-01-closures.html
-/// [function pointers]: fn
-/// [nomicon]: ../../nomicon/hrtb.html
-///
-/// # Examples
-///
-/// ## Using a `FnOnce` parameter
-///
-/// ```
-/// fn consume_with_relish<F>(func: F)
-///     where F: FnOnce() -> String
-/// {
-///     // `func` consumes its captured variables, so it cannot be run more
-///     // than once.
-///     println!("Consumed: {}", func());
-///
-///     println!("Delicious!");
-///
-///     // Attempting to invoke `func()` again will throw a `use of moved
-///     // value` error for `func`.
-/// }
-///
-/// let x = String::from("x");
-/// let consume_and_return_x = move || x;
-/// consume_with_relish(consume_and_return_x);
-///
-/// // `consume_and_return_x` can no longer be invoked at this point
-/// ```
-#[cfg(not(bootstrap))]
 #[lang = "fn_once"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
@@ -507,68 +250,6 @@ pub trait FnOnce<Args: Tuple> {
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 }
 
-#[cfg(bootstrap)]
-mod impls {
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
-    impl<A, F: ?Sized> const Fn<A> for &F
-    where
-        F: ~const Fn<A>,
-    {
-        extern "rust-call" fn call(&self, args: A) -> F::Output {
-            (**self).call(args)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
-    impl<A, F: ?Sized> const FnMut<A> for &F
-    where
-        F: ~const Fn<A>,
-    {
-        extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
-            (**self).call(args)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
-    impl<A, F: ?Sized> const FnOnce<A> for &F
-    where
-        F: ~const Fn<A>,
-    {
-        type Output = F::Output;
-
-        extern "rust-call" fn call_once(self, args: A) -> F::Output {
-            (*self).call(args)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
-    impl<A, F: ?Sized> const FnMut<A> for &mut F
-    where
-        F: ~const FnMut<A>,
-    {
-        extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
-            (*self).call_mut(args)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
-    impl<A, F: ?Sized> const FnOnce<A> for &mut F
-    where
-        F: ~const FnMut<A>,
-    {
-        type Output = F::Output;
-        extern "rust-call" fn call_once(self, args: A) -> F::Output {
-            (*self).call_mut(args)
-        }
-    }
-}
-
-#[cfg(not(bootstrap))]
 mod impls {
     use crate::marker::Tuple;
 
index 461b70c32f36e75016c15f505efb441147cb9cde..8338a5d7e5a2199bb1f2a88b378e78c4f189f091 100644 (file)
     ),
 }
 
-/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
-/// and other panic runtimes. Not intended to be stabilized any time soon, do
-/// not use.
+/// An internal trait used by std to pass data from std to `panic_unwind` and
+/// other panic runtimes. Not intended to be stabilized any time soon, do not
+/// use.
 #[unstable(feature = "std_internals", issue = "none")]
 #[doc(hidden)]
 pub unsafe trait BoxMeUp {
     /// Take full ownership of the contents.
-    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
+    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in core.
     ///
     /// After this method got called, only some dummy default value is left in `self`.
     /// Calling this method twice, or calling `get` after calling this method, is an error.
index 1923155ebc15f388aa484464b5534b70d7e09f3d..0d385c9d1874435ed2bca34ac02c58dfa3554d58 100644 (file)
@@ -157,7 +157,7 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
             write!(formatter, "'{}', ", payload)?
         }
         // NOTE: we cannot use downcast_ref::<String>() here
-        // since String is not available in libcore!
+        // since String is not available in core!
         // The payload is a String when `std::panic!` is called with multiple arguments,
         // but in that case the message is also available.
 
index 9fce78d076bf3e800b5113b9aeaf377393cc0850..48e90e6d794005e7b9bde41b4ac440a93ade37f5 100644 (file)
@@ -1,8 +1,8 @@
-//! Panic support for libcore
+//! Panic support for core
 //!
 //! The core library cannot define panicking, but it does *declare* panicking. This
-//! means that the functions inside of libcore are allowed to panic, but to be
-//! useful an upstream crate must define panicking for libcore to use. The current
+//! means that the functions inside of core are allowed to panic, but to be
+//! useful an upstream crate must define panicking for core to use. The current
 //! interface for panicking is:
 //!
 //! ```
@@ -13,7 +13,7 @@
 //! This definition allows for panicking with any general message, but it does not
 //! allow for failing with a `Box<Any>` value. (`PanicInfo` just contains a `&(dyn Any + Send)`,
 //! for which we fill in a dummy value in `PanicInfo::internal_constructor`.)
-//! The reason for this is that libcore is not allowed to allocate.
+//! The reason for this is that core is not allowed to allocate.
 //!
 //! This module contains a few other panicking functions, but these are just the
 //! necessary lang items for the compiler. All panics are funneled through this
@@ -64,13 +64,17 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     unsafe { panic_impl(&pi) }
 }
 
-/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
-/// (No `fmt` variant as a `fmt::Arguments` needs more space to be passed.)
+/// Like `panic_fmt`, but for non-unwinding panics.
+///
+/// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[track_caller]
+// This attribute has the key side-effect that if the panic handler ignores `can_unwind`
+// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
+// which causes a "panic in a function that cannot unwind".
 #[rustc_nounwind]
-pub fn panic_nounwind(msg: &'static str) -> ! {
+pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
     }
@@ -83,8 +87,6 @@ pub fn panic_nounwind(msg: &'static str) -> ! {
     }
 
     // PanicInfo with the `can_unwind` flag set to false forces an abort.
-    let pieces = [msg];
-    let fmt = fmt::Arguments::new_v1(&pieces, &[]);
     let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
 
     // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
@@ -94,7 +96,7 @@ pub fn panic_nounwind(msg: &'static str) -> ! {
 // Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
 // above.
 
-/// The underlying implementation of libcore's `panic!` macro when no formatting is used.
+/// The underlying implementation of core's `panic!` macro when no formatting is used.
 // never inline unless panic_immediate_abort to avoid code
 // bloat at the call sites as much as possible
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
@@ -112,6 +114,15 @@ pub const fn panic(expr: &'static str) -> ! {
     panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
 }
 
+/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[rustc_nounwind]
+pub fn panic_nounwind(expr: &'static str) -> ! {
+    panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
+}
+
 #[inline]
 #[track_caller]
 #[rustc_diagnostic_item = "panic_str"]
index 3cd3a3b780e9c3621765a93048dc2c9bb509570c..12f762ef1932c7f1bd352fb038d6f1d43c313eaa 100644 (file)
@@ -1,8 +1,8 @@
-//! The libcore prelude
+//! The core prelude
 //!
-//! This module is intended for users of libcore which do not link to libstd as
-//! well. This module is imported by default when `#![no_std]` is used in the
-//! same manner as the standard library's prelude.
+//! This module is intended for users of core which do not link to std as well.
+//! This module is imported by default when `#![no_std]` is used in the same
+//! manner as the standard library's prelude.
 
 #![stable(feature = "core_prelude", since = "1.4.0")]
 
index 2d67d742c689b21e0ca422bd52ca79e1ca7581a4..10525a16f3a66ebd8970cf8a13afb23351c6d22a 100644 (file)
 
 // Do not `doc(no_inline)` so that they become doc items on their own
 // (no public module for them to be re-exported from).
-#[cfg(not(bootstrap))]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use crate::macros::builtin::alloc_error_handler;
-#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
+pub use crate::macros::builtin::{
+    alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
 
 #[unstable(feature = "derive_const", issue = "none")]
-#[cfg(not(bootstrap))]
 pub use crate::macros::builtin::derive_const;
 
 #[unstable(
     issue = "23416",
     reason = "placeholder syntax for type ascription"
 )]
-#[cfg(not(bootstrap))]
 pub use crate::macros::builtin::type_ascribe;
index 64a5290c3a267d6c378ea2680859a9c60fc0fc21..2123147c7e44c1779226bf2b9bce9783bffb990a 100644 (file)
@@ -10,8 +10,7 @@
 /// are likely not to be supported by actual allocators and linkers.
 #[unstable(feature = "ptr_alignment_type", issue = "102070")]
 #[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
 #[repr(transparent)]
 pub struct Alignment(AlignmentEnum);
 
@@ -203,8 +202,7 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
 type AlignmentEnum = AlignmentEnum64;
 
 #[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
 #[repr(u16)]
 enum AlignmentEnum16 {
     _Align1Shl0 = 1 << 0,
@@ -226,8 +224,7 @@ enum AlignmentEnum16 {
 }
 
 #[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
 #[repr(u32)]
 enum AlignmentEnum32 {
     _Align1Shl0 = 1 << 0,
@@ -265,8 +262,7 @@ enum AlignmentEnum32 {
 }
 
 #[derive(Copy, Clone, Eq)]
-#[cfg_attr(bootstrap, derive(PartialEq))]
-#[cfg_attr(not(bootstrap), derive_const(PartialEq))]
+#[derive_const(PartialEq)]
 #[repr(u64)]
 enum AlignmentEnum64 {
     _Align1Shl0 = 1 << 0,
index b6373beac5f76e651d2572ea12333b9c538abe79..0a74c03d70f3a6cf17c95e9a059d49f2960f0945 100644 (file)
@@ -1,6 +1,6 @@
 use super::*;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics;
+use crate::intrinsics::{self, const_eval_select};
 use crate::mem;
 use crate::slice::{self, SliceIndex};
 
@@ -34,12 +34,23 @@ impl<T: ?Sized> *const T {
     #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
     #[inline]
     pub const fn is_null(self) -> bool {
-        // Compare via a cast to a thin pointer, so fat pointers are only
-        // considering their "data" part for null-ness.
-        match (self as *const u8).guaranteed_eq(null()) {
-            None => false,
-            Some(res) => res,
+        #[inline]
+        fn runtime_impl(ptr: *const u8) -> bool {
+            ptr.addr() == 0
         }
+
+        #[inline]
+        const fn const_impl(ptr: *const u8) -> bool {
+            // Compare via a cast to a thin pointer, so fat pointers are only
+            // considering their "data" part for null-ness.
+            match (ptr).guaranteed_eq(null_mut()) {
+                None => false,
+                Some(res) => res,
+            }
+        }
+
+        // SAFETY: The two versions are equivalent at runtime.
+        unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) }
     }
 
     /// Casts to a pointer of another type.
@@ -1350,26 +1361,6 @@ pub const fn align_offset(self, align: usize) -> usize
             panic!("align_offset: align is not a power-of-two");
         }
 
-        #[cfg(bootstrap)]
-        {
-            fn rt_impl<T>(p: *const T, align: usize) -> usize {
-                // SAFETY: `align` has been checked to be a power of 2 above
-                unsafe { align_offset(p, align) }
-            }
-
-            const fn ctfe_impl<T>(_: *const T, _: usize) -> usize {
-                usize::MAX
-            }
-
-            // SAFETY:
-            // It is permissible for `align_offset` to always return `usize::MAX`,
-            // algorithm correctness can not depend on `align_offset` returning non-max values.
-            //
-            // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
-            unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) }
-        }
-
-        #[cfg(not(bootstrap))]
         {
             // SAFETY: `align` has been checked to be a power of 2 above
             unsafe { align_offset(self, align) }
@@ -1406,8 +1397,7 @@ const fn ctfe_impl<T>(_: *const T, _: usize) -> usize {
     /// is never aligned if cast to a type with a stricter alignment than the reference's
     /// underlying allocation.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1433,8 +1423,7 @@ const fn ctfe_impl<T>(_: *const T, _: usize) -> usize {
     /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1460,8 +1449,7 @@ const fn ctfe_impl<T>(_: *const T, _: usize) -> usize {
     /// If a pointer is created from a fixed address, this function behaves the same during
     /// runtime and compiletime.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1537,8 +1525,7 @@ pub const fn is_aligned(self) -> bool
     /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
     /// cannot be stricter aligned than the reference's underlying allocation.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1563,8 +1550,7 @@ pub const fn is_aligned(self) -> bool
     /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1588,8 +1574,7 @@ pub const fn is_aligned(self) -> bool
     /// If a pointer is created from a fixed address, this function behaves the same during
     /// runtime and compiletime.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1613,11 +1598,22 @@ pub const fn is_aligned_to(self, align: usize) -> bool {
             panic!("is_aligned_to: align is not a power-of-two");
         }
 
-        // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
-        // The cast to `()` is used to
-        //   1. deal with fat pointers; and
-        //   2. ensure that `align_offset` doesn't actually try to compute an offset.
-        self.cast::<()>().align_offset(align) == 0
+        #[inline]
+        fn runtime_impl(ptr: *const (), align: usize) -> bool {
+            ptr.addr() & (align - 1) == 0
+        }
+
+        #[inline]
+        const fn const_impl(ptr: *const (), align: usize) -> bool {
+            // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
+            // The cast to `()` is used to
+            //   1. deal with fat pointers; and
+            //   2. ensure that `align_offset` doesn't actually try to compute an offset.
+            ptr.align_offset(align) == 0
+        }
+
+        // SAFETY: The two versions are equivalent at runtime.
+        unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
     }
 }
 
index a8604843e96319c679441affd4a7a32972d44fe5..2ea032d4affe052abb3898f2182ccccb241040b5 100644 (file)
@@ -50,7 +50,7 @@
 ///
 /// [`to_raw_parts`]: *const::to_raw_parts
 #[lang = "pointee_trait"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl]
 pub trait Pointee {
     /// The type for metadata in pointers and references to `Self`.
     #[lang = "metadata_type"]
index 7a5d9a7059459986cda025f9caa317e0ae951d1b..d70fb70c79fa4dc6dacc84297e67a062235bd8d8 100644 (file)
@@ -1,6 +1,6 @@
 use super::*;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics;
+use crate::intrinsics::{self, const_eval_select};
 use crate::slice::{self, SliceIndex};
 
 impl<T: ?Sized> *mut T {
@@ -33,12 +33,23 @@ impl<T: ?Sized> *mut T {
     #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
     #[inline]
     pub const fn is_null(self) -> bool {
-        // Compare via a cast to a thin pointer, so fat pointers are only
-        // considering their "data" part for null-ness.
-        match (self as *mut u8).guaranteed_eq(null_mut()) {
-            None => false,
-            Some(res) => res,
+        #[inline]
+        fn runtime_impl(ptr: *mut u8) -> bool {
+            ptr.addr() == 0
         }
+
+        #[inline]
+        const fn const_impl(ptr: *mut u8) -> bool {
+            // Compare via a cast to a thin pointer, so fat pointers are only
+            // considering their "data" part for null-ness.
+            match (ptr).guaranteed_eq(null_mut()) {
+                None => false,
+                Some(res) => res,
+            }
+        }
+
+        // SAFETY: The two versions are equivalent at runtime.
+        unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
     }
 
     /// Casts to a pointer of another type.
@@ -1618,26 +1629,6 @@ pub const fn align_offset(self, align: usize) -> usize
             panic!("align_offset: align is not a power-of-two");
         }
 
-        #[cfg(bootstrap)]
-        {
-            fn rt_impl<T>(p: *mut T, align: usize) -> usize {
-                // SAFETY: `align` has been checked to be a power of 2 above
-                unsafe { align_offset(p, align) }
-            }
-
-            const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
-                usize::MAX
-            }
-
-            // SAFETY:
-            // It is permissible for `align_offset` to always return `usize::MAX`,
-            // algorithm correctness can not depend on `align_offset` returning non-max values.
-            //
-            // As such the behaviour can't change after replacing `align_offset` with `usize::MAX`, only performance can.
-            unsafe { intrinsics::const_eval_select((self, align), ctfe_impl, rt_impl) }
-        }
-
-        #[cfg(not(bootstrap))]
         {
             // SAFETY: `align` has been checked to be a power of 2 above
             unsafe { align_offset(self, align) }
@@ -1674,8 +1665,7 @@ const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
     /// is never aligned if cast to a type with a stricter alignment than the reference's
     /// underlying allocation.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     /// #![feature(const_mut_refs)]
@@ -1702,8 +1692,7 @@ const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
     /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1730,8 +1719,7 @@ const fn ctfe_impl<T>(_: *mut T, _: usize) -> usize {
     /// If a pointer is created from a fixed address, this function behaves the same during
     /// runtime and compiletime.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1807,8 +1795,7 @@ pub const fn is_aligned(self) -> bool
     /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
     /// cannot be stricter aligned than the reference's underlying allocation.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     /// #![feature(const_mut_refs)]
@@ -1834,8 +1821,7 @@ pub const fn is_aligned(self) -> bool
     /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
     /// pointer is aligned, even if the compiletime pointer wasn't aligned.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1860,8 +1846,7 @@ pub const fn is_aligned(self) -> bool
     /// If a pointer is created from a fixed address, this function behaves the same during
     /// runtime and compiletime.
     ///
-    #[cfg_attr(bootstrap, doc = "```ignore")]
-    #[cfg_attr(not(bootstrap), doc = "```")]
+    /// ```
     /// #![feature(pointer_is_aligned)]
     /// #![feature(const_pointer_is_aligned)]
     ///
@@ -1885,11 +1870,22 @@ pub const fn is_aligned_to(self, align: usize) -> bool {
             panic!("is_aligned_to: align is not a power-of-two");
         }
 
-        // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
-        // The cast to `()` is used to
-        //   1. deal with fat pointers; and
-        //   2. ensure that `align_offset` doesn't actually try to compute an offset.
-        self.cast::<()>().align_offset(align) == 0
+        #[inline]
+        fn runtime_impl(ptr: *mut (), align: usize) -> bool {
+            ptr.addr() & (align - 1) == 0
+        }
+
+        #[inline]
+        const fn const_impl(ptr: *mut (), align: usize) -> bool {
+            // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
+            // The cast to `()` is used to
+            //   1. deal with fat pointers; and
+            //   2. ensure that `align_offset` doesn't actually try to compute an offset.
+            ptr.align_offset(align) == 0
+        }
+
+        // SAFETY: The two versions are equivalent at runtime.
+        unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
     }
 }
 
index 87f77b7f21d62e8e64cda64c2dfd076107296338..b8c0c3fd9493285b10117fb8ede4d341ee733607 100644 (file)
@@ -3,7 +3,7 @@
 //! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort,
 //! published at: <https://github.com/orlp/pdqsort>
 //!
-//! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our
+//! Unstable sorting is compatible with core because it doesn't allocate memory, unlike our
 //! stable sorting implementation.
 
 use crate::cmp;
index 24083ee6af44f34f2362df3913445b5c906a0aae..d969475aa484fd5a740a2f2c6895f0a24c2b7e3d 100644 (file)
@@ -585,16 +585,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     #[inline]
     fn get_end(&mut self) -> Option<&'a str> {
-        if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
+        if !self.finished {
             self.finished = true;
-            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-            unsafe {
-                let string = self.matcher.haystack().get_unchecked(self.start..self.end);
-                Some(string)
+
+            if self.allow_trailing_empty || self.end - self.start > 0 {
+                // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+                let string = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) };
+                return Some(string);
             }
-        } else {
-            None
         }
+
+        None
     }
 
     #[inline]
@@ -716,14 +717,14 @@ fn next_back_inclusive(&mut self) -> Option<&'a str>
     }
 
     #[inline]
-    fn as_str(&self) -> &'a str {
+    fn remainder(&self) -> Option<&'a str> {
         // `Self::get_end` doesn't change `self.start`
         if self.finished {
-            return "";
+            return None;
         }
 
         // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-        unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+        Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) })
     }
 }
 
@@ -746,44 +747,48 @@ fn as_str(&self) -> &'a str {
 }
 
 impl<'a, P: Pattern<'a>> Split<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".split(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplit<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".rsplit(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// assert_eq!(split.remainder(), Some("Mary had a little"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -806,44 +811,48 @@ pub fn as_str(&self) -> &'a str {
 }
 
 impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "A..B..".split_terminator('.');
-    /// assert_eq!(split.as_str(), "A..B..");
+    /// assert_eq!(split.remainder(), Some("A..B.."));
     /// split.next();
-    /// assert_eq!(split.as_str(), ".B..");
+    /// assert_eq!(split.remainder(), Some(".B.."));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "A..B..".rsplit_terminator('.');
-    /// assert_eq!(split.as_str(), "A..B..");
+    /// assert_eq!(split.remainder(), Some("A..B.."));
     /// split.next();
-    /// assert_eq!(split.as_str(), "A..B");
+    /// assert_eq!(split.remainder(), Some("A..B"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -905,8 +914,8 @@ fn next_back(&mut self) -> Option<&'a str>
     }
 
     #[inline]
-    fn as_str(&self) -> &'a str {
-        self.iter.as_str()
+    fn remainder(&self) -> Option<&'a str> {
+        self.iter.remainder()
     }
 }
 
@@ -929,44 +938,48 @@ fn as_str(&self) -> &'a str {
 }
 
 impl<'a, P: Pattern<'a>> SplitN<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".splitn(3, ' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// assert_eq!(split.remainder(), Some("Mary had a little"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -1239,22 +1252,22 @@ impl<'a> SplitWhitespace<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_whitespace_as_str)]
+    /// #![feature(str_split_whitespace_remainder)]
     ///
     /// let mut split = "Mary had a little lamb".split_whitespace();
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     ///
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     ///
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.inner.iter.as_str()
+    #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.inner.iter.remainder()
     }
 }
 
@@ -1290,32 +1303,34 @@ fn next_back(&mut self) -> Option<&'a str> {
 impl FusedIterator for SplitAsciiWhitespace<'_> {}
 
 impl<'a> SplitAsciiWhitespace<'a> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_whitespace_as_str)]
+    /// #![feature(str_split_whitespace_remainder)]
     ///
     /// let mut split = "Mary had a little lamb".split_ascii_whitespace();
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     ///
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     ///
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
+    #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
         if self.inner.iter.iter.finished {
-            return "";
+            return None;
         }
 
         // SAFETY: Slice is created from str.
-        unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }
+        Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) })
     }
 }
 
@@ -1358,23 +1373,25 @@ fn next_back(&mut self) -> Option<&'a str> {
 impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
 
 impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_inclusive_as_str)]
+    /// #![feature(str_split_inclusive_remainder)]
     /// let mut split = "Mary had a little lamb".split_inclusive(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_inclusive_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
index 863ded5e5ec037836586366e1ac2a2a41a3bbe02..ab2f8520ecb33d969a479891fdca82997b90144e 100644 (file)
@@ -368,7 +368,7 @@ pub const fn as_bytes(&self) -> &[u8] {
     #[inline(always)]
     pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
         // SAFETY: the cast from `&str` to `&[u8]` is safe since `str`
-        // has the same layout as `&[u8]` (only libstd can make this guarantee).
+        // has the same layout as `&[u8]` (only std can make this guarantee).
         // The pointer dereference is safe since it comes from a mutable reference which
         // is guaranteed to be valid for writes.
         unsafe { &mut *(self as *mut str as *mut [u8]) }
index f1dc4f7b575aaeb03deaaa41ace566fdbb0ec36e..25b61c0e66641d9beaf8a11fd88afef387317ae4 100644 (file)
@@ -9,7 +9,7 @@
 /// scheduled to receive a wakeup instead.
 #[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
-#[cfg_attr(not(bootstrap), lang = "Poll")]
+#[lang = "Poll"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub enum Poll<T> {
     /// Represents that a value is immediately ready.
index 1b7578376b42bac72c1232b9078acf509330aa84..a4425fd234a4e22ad79ee3dfd4418464d80723ae 100644 (file)
@@ -181,6 +181,9 @@ pub struct Context<'a> {
     // are contravariant while return-position lifetimes are
     // covariant).
     _marker: PhantomData<fn(&'a ()) -> &'a ()>,
+    // Ensure `Context` is `!Send` and `!Sync` in order to allow
+    // for future `!Send` and / or `!Sync` fields.
+    _marker2: PhantomData<*mut ()>,
 }
 
 impl<'a> Context<'a> {
@@ -190,7 +193,7 @@ impl<'a> Context<'a> {
     #[must_use]
     #[inline]
     pub const fn from_waker(waker: &'a Waker) -> Self {
-        Context { waker, _marker: PhantomData }
+        Context { waker, _marker: PhantomData, _marker2: PhantomData }
     }
 
     /// Returns a reference to the [`Waker`] for the current task.
index 72fa059b787df48bf7c67dea1964c3696038be5b..e1faa407d54c55206b50477caba6e89482592d1f 100644 (file)
@@ -17,7 +17,7 @@
 #[stable(feature = "unicode_version", since = "1.45.0")]
 pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION;
 
-// For use in liballoc, not re-exported in libstd.
+// For use in alloc, not re-exported in std.
 pub use unicode_data::{
     case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions,
 };
index e98dac8d12ef449d6d54a8bb1a2e714d68cbea98..a8f6b7ebb925029d799c1b74af314c2f815937c1 100644 (file)
@@ -131,7 +131,6 @@ fn type_name_of_val<T>(_: T) -> &'static str {
     assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
 }
 
-#[cfg(not(bootstrap))]
 #[test]
 fn dyn_type_name() {
     trait Foo {
index 70fcc6d2d4bf7d9d1de717d017073ca85c9e97b1..c7c3c479b71db92af495eaa0407940efcdd622e9 100644 (file)
@@ -106,6 +106,12 @@ fn lazy_new() {
     assert_eq!(called.get(), 1);
 }
 
+// Check that we can infer `T` from closure's type.
+#[test]
+fn lazy_type_inference() {
+    let _ = LazyCell::new(|| ());
+}
+
 #[test]
 fn aliasing_in_get() {
     let x = OnceCell::new();
index 99d4a40c4c962816f5637333c421579f518c6082..c910cb65c55def0f32dc6c9fb7294965d79b2d54 100644 (file)
 mod tuple;
 mod unicode;
 mod waker;
+
+/// Copied from `std::test_helpers::test_rng`, see that function for rationale.
+#[track_caller]
+#[allow(dead_code)] // Not used in all configurations.
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+    use core::hash::{BuildHasher, Hash, Hasher};
+    let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+    core::panic::Location::caller().hash(&mut hasher);
+    let hc64 = hasher.finish();
+    let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+    let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+    rand::SeedableRng::from_seed(seed)
+}
index 1cfb4fd9fd186e55cc84c3b641bdf37e10858d6e..f7740a114e738d84f86b87a083cd92b82d5dc1ad 100644 (file)
@@ -77,7 +77,6 @@ fn align_of_val_basic() {
 }
 
 #[test]
-#[cfg(not(bootstrap))] // stage 0 doesn't have the fix yet, so the test fails
 fn align_of_val_raw_packed() {
     #[repr(C, packed)]
     struct B {
index d0950039314ac571befd78339ffe40b18ebf10cd..0084c1c814e2d6470faae5b04090525c741aa38e 100644 (file)
@@ -9,8 +9,6 @@
 use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
 
 use rand::distributions::{Distribution, Uniform};
-use rand::rngs::StdRng;
-use rand::SeedableRng;
 
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
@@ -92,7 +90,7 @@ pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
     if cfg!(target_os = "emscripten") {
         return; // using rng pulls in i128 support, which doesn't work
     }
-    let mut rng = StdRng::from_entropy();
+    let mut rng = crate::test_rng();
     let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
     iterate("f32_random_equivalence_test", k, n, f, g, |_| {
         let x = f32::from_bits(f32_range.sample(&mut rng));
@@ -108,7 +106,7 @@ pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
     if cfg!(target_os = "emscripten") {
         return; // using rng pulls in i128 support, which doesn't work
     }
-    let mut rng = StdRng::from_entropy();
+    let mut rng = crate::test_rng();
     let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
     iterate("f64_random_equivalence_test", k, n, f, g, |_| {
         let x = f64::from_bits(f64_range.sample(&mut rng));
index 90bc83510803f2185d4f8a3ec83e19343cc5eda8..80d30f14c66b24d137dbbea5270566051eda363e 100644 (file)
@@ -359,7 +359,6 @@ fn align_offset_zst() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn align_offset_zst_const() {
     const {
         // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
@@ -397,7 +396,6 @@ fn align_offset_stride_one() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn align_offset_stride_one_const() {
     const {
         // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
@@ -493,7 +491,6 @@ unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn align_offset_various_strides_const() {
     const unsafe fn test_stride<T>(ptr: *const T, numptr: usize, align: usize) {
         let mut expected = usize::MAX;
@@ -561,7 +558,6 @@ fn align_offset_various_strides_const() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn align_offset_with_provenance_const() {
     const {
         // On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4.
@@ -681,7 +677,6 @@ fn align_offset_issue_103361() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn align_offset_issue_103361_const() {
     #[cfg(target_pointer_width = "64")]
     const SIZE: usize = 1 << 47;
@@ -715,7 +710,6 @@ fn is_aligned() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn is_aligned_const() {
     const {
         let data = 42;
@@ -734,18 +728,6 @@ fn is_aligned_const() {
     }
 }
 
-#[test]
-#[cfg(bootstrap)]
-fn is_aligned_const() {
-    const {
-        let data = 42;
-        let ptr: *const i32 = &data;
-        // The bootstrap compiler always returns false for is_aligned.
-        assert!(!ptr.is_aligned());
-        assert!(!ptr.is_aligned_to(1));
-    }
-}
-
 #[test]
 fn offset_from() {
     let mut a = [0; 5];
@@ -825,7 +807,7 @@ fn metadata_eq_method_address<T: ?Sized>() -> usize {
     }
     // "Synthetic" trait impls generated by the compiler like those of `Pointee`
     // are not checked for bounds of associated type.
-    // So with a buggy libcore we could have both:
+    // So with a buggy core we could have both:
     // * `<dyn Display as Pointee>::Metadata == DynMetadata`
     // * `DynMetadata: !PartialEq`
     // … and cause an ICE here:
index 4e06e0f43988687dc514a36cfe157ffc8b5b5957..fd35d96c3fef814bd7952fb8b13afbcd7f31354f 100644 (file)
@@ -1805,7 +1805,7 @@ fn brute_force_rotate_test_1() {
 fn sort_unstable() {
     use core::cmp::Ordering::{Equal, Greater, Less};
     use core::slice::heapsort;
-    use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
+    use rand::{seq::SliceRandom, Rng};
 
     // Miri is too slow (but still need to `chain` to make the types match)
     let lens = if cfg!(miri) { (2..20).chain(0..0) } else { (2..25).chain(500..510) };
@@ -1813,7 +1813,7 @@ fn sort_unstable() {
 
     let mut v = [0; 600];
     let mut tmp = [0; 600];
-    let mut rng = StdRng::from_entropy();
+    let mut rng = crate::test_rng();
 
     for len in lens {
         let v = &mut v[0..len];
@@ -1879,11 +1879,10 @@ fn sort_unstable() {
 #[cfg_attr(miri, ignore)] // Miri is too slow
 fn select_nth_unstable() {
     use core::cmp::Ordering::{Equal, Greater, Less};
-    use rand::rngs::StdRng;
     use rand::seq::SliceRandom;
-    use rand::{Rng, SeedableRng};
+    use rand::Rng;
 
-    let mut rng = StdRng::from_entropy();
+    let mut rng = crate::test_rng();
 
     for len in (2..21).chain(500..501) {
         let mut orig = vec![0; len];
index ed939ca7139a58da190d41ceb6f366db74e683b5..f5066343af20a78d41475aa65ca67c1fa17200df 100644 (file)
@@ -1 +1 @@
-// All `str` tests live in liballoc/tests
+// All `str` tests live in library/alloc/tests/str.rs
index 56be30e9282452b8b9aa0a8b59b9255f072dd350..163b34c9648529463304ec451c8cbff083d2159c 100644 (file)
@@ -1,4 +1,4 @@
-use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use core::task::{Poll, RawWaker, RawWakerVTable, Waker};
 
 #[test]
 fn poll_const() {
@@ -21,9 +21,5 @@ fn waker_const() {
 
     static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) };
 
-    static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
-
-    static WAKER_REF: &'static Waker = CONTEXT.waker();
-
-    WAKER_REF.wake_by_ref();
+    WAKER.wake_by_ref();
 }
index cba8ef25db62687021f8eacf3f837da1fb2251a9..a3cebf99c5342c3078f2565b3dbb336ca5fd59cf 100644 (file)
@@ -61,7 +61,7 @@ unsafe fn abort() -> ! {
             //
             // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
             //
-            // Note: this is the same implementation as in libstd's `abort_internal`
+            // Note: this is the same implementation as in std's `abort_internal`
             unsafe fn abort() -> ! {
                 #[allow(unused)]
                 const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
@@ -89,7 +89,7 @@ unsafe fn abort() -> ! {
 // This... is a bit of an oddity. The tl;dr; is that this is required to link
 // correctly, the longer explanation is below.
 //
-// Right now the binaries of libcore/libstd that we ship are all compiled with
+// Right now the binaries of core/std that we ship are all compiled with
 // `-C panic=unwind`. This is done to ensure that the binaries are maximally
 // compatible with as many situations as possible. The compiler, however,
 // requires a "personality function" for all functions compiled with `-C
@@ -109,7 +109,7 @@ unsafe fn abort() -> ! {
 // library just defines this symbol so there's at least some personality
 // somewhere.
 //
-// Essentially this symbol is just defined to get wired up to libcore/libstd
+// Essentially this symbol is just defined to get wired up to core/std
 // binaries, but it should never be called as we don't link in an unwinding
 // runtime at all.
 pub mod personalities {
index 7e7180a38e2f23d6c76b3886a503ebb20832bec6..ea3c9a7a663c23d6bfc66d7a5c4c1420ec28c122 100644 (file)
 }
 
 extern "C" {
-    /// Handler in libstd called when a panic object is dropped outside of
+    /// Handler in std called when a panic object is dropped outside of
     /// `catch_unwind`.
     fn __rust_drop_panic() -> !;
 
-    /// Handler in libstd called when a foreign exception is caught.
+    /// Handler in std called when a foreign exception is caught.
     fn __rust_foreign_exception() -> !;
 }
 
index 506b2a773cc49f997763493d0704d2fbed527ac1..52a08cad9110fa18316478ad300f27788706ee5a 100644 (file)
@@ -356,7 +356,7 @@ fn clone(&self) -> Self {
 
 fn maybe_install_panic_hook(force_show_panics: bool) {
     // Hide the default panic output within `proc_macro` expansions.
-    // NB. the server can't do this because it may use a different libstd.
+    // NB. the server can't do this because it may use a different std.
     static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
     HIDE_PANICS_DURING_EXPANSION.call_once(|| {
         let prev = panic::take_hook();
index 4b1e412e24b709e2ed77e6dd1ccebb3be2a11a1d..17bd0a1b33646643e724ae73a00ac38b34033f4e 100644 (file)
@@ -15,9 +15,9 @@
 /// Type alias for a hashmap using the `fx` hash algorithm.
 pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
 
-/// A speedy hash algorithm for use within rustc. The hashmap in liballoc
-/// by default uses SipHash which isn't quite as speedy as we want. In the
-/// compiler we're not really worried about DOS attempts, so we use a fast
+/// A speedy hash algorithm for use within rustc. The hashmap in alloc by
+/// default uses SipHash which isn't quite as speedy as we want. In the compiler
+/// we're not really worried about DOS attempts, so we use a fast
 /// non-cryptographic hash.
 ///
 /// This is the same as the algorithm used by Firefox -- which is a homespun
index 8202c40d63170464fe96cb2bc49f8df605100c20..2ea87d866ff3eaf584973afab015d989e0a364c1 100644 (file)
@@ -112,7 +112,7 @@ fn dispatch(&mut self, mut buf: Buffer) -> Buffer {
                                 $name::$method(server, $($arg),*)
                             };
                             // HACK(eddyb) don't use `panic::catch_unwind` in a panic.
-                            // If client and server happen to use the same `libstd`,
+                            // If client and server happen to use the same `std`,
                             // `catch_unwind` asserts that the panic counter was 0,
                             // even when the closure passed to it didn't panic.
                             let r = if thread::panicking() {
index c38a8d2f204e4126cf9a2ecad1d653c0748e9ca7..87db7af44ae09590625561b3b0d26340131f403b 100644 (file)
@@ -3,7 +3,7 @@
 
 // See rustc-std-workspace-core for why this crate is needed.
 
-// Rename the crate to avoid conflicting with the alloc module in liballoc.
+// Rename the crate to avoid conflicting with the alloc module in alloc.
 extern crate alloc as foo;
 
 pub use foo::*;
index 29b5a468bf4c502d582e0d369067b8c50af5eaea..adf521d9b94a124544268303b51f52e8e5ef2c05 100644 (file)
@@ -33,7 +33,8 @@ default-features = false
 features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
 
 [dev-dependencies]
-rand = "0.7"
+rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+rand_xorshift = "0.3.0"
 
 [target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
 dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
index 61c1ff578b2cad4ec3f8c46b09bd71ab80ef0d1b..c5a5991cc81c47d340a3b7b113c56339671acd7e 100644 (file)
@@ -338,7 +338,7 @@ fn default_alloc_error_hook(layout: Layout) {
 
     #[allow(unused_unsafe)]
     if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
-        panic!("memory allocation of {} bytes failed\n", layout.size());
+        panic!("memory allocation of {} bytes failed", layout.size());
     } else {
         rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
     }
index 9cb74f951dd3721df31b3e74086bbe7a3f3e9e91..7543ffadd4140f5dc99441e5d3a57674252362d2 100644 (file)
 //!
 //! ## Platform support
 //!
-//! Not all platforms that libstd compiles for support capturing backtraces.
-//! Some platforms simply do nothing when capturing a backtrace. To check
-//! whether the platform supports capturing backtraces you can consult the
-//! `BacktraceStatus` enum as a result of `Backtrace::status`.
+//! Not all platforms that std compiles for support capturing backtraces. Some
+//! platforms simply do nothing when capturing a backtrace. To check whether the
+//! platform supports capturing backtraces you can consult the `BacktraceStatus`
+//! enum as a result of `Backtrace::status`.
 //!
 //! Like above with accuracy platform support is done on a best effort basis.
 //! Sometimes libraries might not be available at runtime or something may go
index 65634f2063f36da25633548a6be59ce94a7dda21..6b89518e2e26cd69bdb606b44dfc38815c09cab3 100644 (file)
@@ -3,7 +3,8 @@
 use super::RandomState;
 use crate::assert_matches::assert_matches;
 use crate::cell::RefCell;
-use rand::{thread_rng, Rng};
+use crate::test_helpers::test_rng;
+use rand::Rng;
 use realstd::collections::TryReserveErrorKind::*;
 
 // https://github.com/rust-lang/rust/issues/62301
@@ -710,16 +711,16 @@ fn check(m: &HashMap<i32, ()>) {
     }
 
     let mut m = HashMap::new();
-    let mut rng = thread_rng();
+    let mut rng = test_rng();
 
     // Populate the map with some items.
     for _ in 0..50 {
-        let x = rng.gen_range(-1010);
+        let x = rng.gen_range(-10..10);
         m.insert(x, ());
     }
 
     for _ in 0..1000 {
-        let x = rng.gen_range(-1010);
+        let x = rng.gen_range(-10..10);
         match m.entry(x) {
             Vacant(_) => {}
             Occupied(e) => {
index cee884145c7116fd3f695389b94a4ad3501475ca..b59f89d321c47ad93f61b53950127157304e8a63 100644 (file)
@@ -317,7 +317,7 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
     ///
     /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
     /// set.retain(|&k| k % 2 == 0);
-    /// assert_eq!(set.len(), 3);
+    /// assert_eq!(set, HashSet::from([2, 4, 6]));
     /// ```
     ///
     /// # Performance
index b385ebde439794e9fc1b3fa0e526aec447a15031..eb582be012bd54d72940ab3c694d99c769e0b236 100644 (file)
@@ -10,7 +10,7 @@
 use crate::thread;
 use crate::time::{Duration, Instant};
 
-use rand::{rngs::StdRng, RngCore, SeedableRng};
+use rand::RngCore;
 
 #[cfg(unix)]
 use crate::os::unix::fs::symlink as symlink_dir;
@@ -1181,7 +1181,7 @@ fn _assert_send_sync<T: Send + Sync>() {}
 #[test]
 fn binary_file() {
     let mut bytes = [0; 1024];
-    StdRng::from_entropy().fill_bytes(&mut bytes);
+    crate::test_helpers::test_rng().fill_bytes(&mut bytes);
 
     let tmpdir = tmpdir();
 
@@ -1194,7 +1194,7 @@ fn binary_file() {
 #[test]
 fn write_then_read() {
     let mut bytes = [0; 1024];
-    StdRng::from_entropy().fill_bytes(&mut bytes);
+    crate::test_helpers::test_rng().fill_bytes(&mut bytes);
 
     let tmpdir = tmpdir();
 
index 781ae03ad45dcb865c66d90b45a6109d28c7fad8..601c01c2128c816757c103d3a04f3c4c0dd8646c 100644 (file)
@@ -166,7 +166,7 @@ pub(super) fn new_custom(b: Box<Custom>) -> Self {
         // `new_unchecked` is safe.
         let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
-        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        // only run in std's tests, unless the user uses -Zbuild-std)
         debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
         res
     }
@@ -177,7 +177,7 @@ pub(super) fn new_os(code: i32) -> Self {
         // 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);
         // quickly smoke-check we encoded the right thing (This generally will
-        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        // only run in std's tests, unless the user uses -Zbuild-std)
         debug_assert!(
             matches!(res.data(), ErrorData::Os(c) if c == code),
             "repr(os) encoding failed for {code}"
@@ -191,7 +191,7 @@ pub(super) fn new_simple(kind: ErrorKind) -> Self {
         // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
         let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
-        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        // only run in std's tests, unless the user uses -Zbuild-std)
         debug_assert!(
             matches!(res.data(), ErrorData::Simple(k) if k == kind),
             "repr(simple) encoding failed {:?}",
@@ -348,7 +348,7 @@ macro_rules! from_prim {
 // that our encoding relies on for correctness and soundness. (Some of these are
 // a bit overly thorough/cautious, admittedly)
 //
-// If any of these are hit on a platform that libstd supports, we should likely
+// If any of these are hit on a platform that std supports, we should likely
 // just use `repr_unpacked.rs` there instead (unless the fix is easy).
 macro_rules! static_assert {
     ($condition:expr) => {
index 23a13523fc275be62e588a04935d0ffa12f51d6f..de528e85368cbf5ed6b471b7411f4e3b97b53ca4 100644 (file)
@@ -2137,8 +2137,10 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
     }
 
     /// Read all bytes until a newline (the `0xA` byte) is reached, and append
-    /// them to the provided buffer. You do not need to clear the buffer before
-    /// appending.
+    /// them to the provided `String` buffer.
+    ///
+    /// Previous content of the buffer will be preserved. To avoid appending to
+    /// the buffer, you need to [`clear`] it first.
     ///
     /// This function will read bytes from the underlying stream until the
     /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
@@ -2151,9 +2153,11 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
     ///
     /// This function is blocking and should be used carefully: it is possible for
     /// an attacker to continuously send bytes without ever sending a newline
-    /// or EOF.
+    /// or EOF. You can use [`take`] to limit the maximum number of bytes read.
     ///
     /// [`Ok(0)`]: Ok
+    /// [`clear`]: String::clear
+    /// [`take`]: crate::io::Read::take
     ///
     /// # Errors
     ///
index 1141a957d8712de984813a86117c927af63be7f1..14bfef4c7aad9bbefea6e896a749d2a67d8480f3 100644 (file)
@@ -10,9 +10,8 @@
 use crate::fs::File;
 use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
 use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
+use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard};
 use crate::sys::stdio;
-use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 
 type LocalStream = Arc<Mutex<Vec<u8>>>;
 
index 65d4c3c891ea689c2ec4c9267caa248141382d6a..a7e13f5b866b53058f0f995f5818e739c47c09de 100644 (file)
@@ -14,7 +14,7 @@
 //! # How to read this documentation
 //!
 //! If you already know the name of what you are looking for, the fastest way to
-//! find it is to use the <a href="#" onclick="focusSearchBar();">search
+//! find it is to use the <a href="#" onclick="window.searchState.focus();">search
 //! bar</a> at the top of the page.
 //!
 //! Otherwise, you may want to jump to one of these useful sections:
     no_global_oom_handling,
     not(no_global_oom_handling)
 ))]
-// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
+// To run std tests without x.py without ending up with two copies of std, Miri needs to be
 // able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
 // rustc itself never sets the feature, so this line has no affect there.
 #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
 pub mod sync;
 pub mod time;
 
-// Pull in `std_float` crate  into libstd. The contents of
+// Pull in `std_float` crate  into std. The contents of
 // `std_float` are in a different repository: rust-lang/portable-simd.
 #[path = "../../portable-simd/crates/std_float/src/lib.rs"]
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
@@ -602,7 +602,7 @@ pub mod arch {
 #[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
 mod backtrace_rs;
 
-// Re-export macros defined in libcore.
+// Re-export macros defined in core.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::{
@@ -610,7 +610,7 @@ pub mod arch {
     unimplemented, unreachable, write, writeln,
 };
 
-// Re-export built-in macros defined through libcore.
+// Re-export built-in macros defined through core.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 #[allow(deprecated)]
 pub use core::{
@@ -652,3 +652,30 @@ mod sealed {
     #[unstable(feature = "sealed", issue = "none")]
     pub trait Sealed {}
 }
+
+#[cfg(test)]
+#[allow(dead_code)] // Not used in all configurations.
+pub(crate) mod test_helpers {
+    /// Test-only replacement for `rand::thread_rng()`, which is unusable for
+    /// us, as we want to allow running stdlib tests on tier-3 targets which may
+    /// not have `getrandom` support.
+    ///
+    /// Does a bit of a song and dance to ensure that the seed is different on
+    /// each call (as some tests sadly rely on this), but doesn't try that hard.
+    ///
+    /// This is duplicated in the `core`, `alloc` test suites (as well as
+    /// `std`'s integration tests), but figuring out a mechanism to share these
+    /// seems far more painful than copy-pasting a 7 line function a couple
+    /// times, given that even under a perma-unstable feature, I don't think we
+    /// want to expose types from `rand` from `std`.
+    #[track_caller]
+    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+        use core::hash::{BuildHasher, Hash, Hasher};
+        let mut hasher = crate::collections::hash_map::RandomState::new().build_hasher();
+        core::panic::Location::caller().hash(&mut hasher);
+        let hc64 = hasher.finish();
+        let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+        rand::SeedableRng::from_seed(seed)
+    }
+}
index 6e4ba1404e55172333fe7897b6f78e62e07c4486..fcc5cfafd808d0cc2066366fe12d0c9cb55dbb7c 100644 (file)
@@ -3,6 +3,7 @@
 //! This module contains a set of macros which are exported from the standard
 //! library. Each macro is available for use when linking against the standard
 //! library.
+// ignore-tidy-dbg
 
 #[doc = include_str!("../../core/src/macros/panic.md")]
 #[macro_export]
index 5453853e1381abacf285cb10cc786a4e26af4cb6..07f08c1b5869d314ef0924f5345b5780b936b8c3 100644 (file)
@@ -1195,6 +1195,9 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
 
     /// An IPv6 address representing localhost: `::1`.
     ///
+    /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
+    /// languages.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1203,11 +1206,15 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
     /// let addr = Ipv6Addr::LOCALHOST;
     /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
     /// ```
+    #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
+    #[doc(alias = "in6addr_loopback")]
     #[stable(feature = "ip_constructors", since = "1.30.0")]
     pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
 
     /// An IPv6 address representing the unspecified address: `::`
     ///
+    /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1216,6 +1223,8 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
     /// let addr = Ipv6Addr::UNSPECIFIED;
     /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
     /// ```
+    #[doc(alias = "IN6ADDR_ANY_INIT")]
+    #[doc(alias = "in6addr_any")]
     #[stable(feature = "ip_constructors", since = "1.30.0")]
     pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
 
index c4f022de021efa8e8ec2d80bb324bbb207b30180..9fa8f5702a8438b59c756f161d8a91df943f5337 100644 (file)
@@ -114,6 +114,9 @@ impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S>
 /// aborting the process as well. This function *only* catches unwinding panics,
 /// not those that abort the process.
 ///
+/// Note that if a custom panic hook has been set, it will be invoked before
+/// the panic is caught, before unwinding.
+///
 /// Also note that unwinding into Rust code with a foreign exception (e.g.
 /// an exception thrown from C++ code) is undefined behavior.
 ///
index 1039835bbbdfe5430d9f5175ed28b7b4d11ef883..b30dd8eecd84c210d709d998cd15a95e77b5d2dc 100644 (file)
@@ -517,7 +517,7 @@ pub fn panicking() -> bool {
     !panic_count::count_is_zero()
 }
 
-/// Entry point of panics from the libcore crate (`panic_impl` lang item).
+/// Entry point of panics from the core crate (`panic_impl` lang item).
 #[cfg(not(test))]
 #[panic_handler]
 pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
@@ -699,7 +699,11 @@ fn rust_panic_with_hook(
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
-        rtprintpanic!("thread panicked while panicking. aborting.\n");
+        if !can_unwind {
+            rtprintpanic!("thread caused non-unwinding panic. aborting.\n");
+        } else {
+            rtprintpanic!("thread panicked while panicking. aborting.\n");
+        }
         crate::sys::abort_internal();
     }
 
index 73b5056e932672bc85e38a96de4920c10e3cb31e..82d68369312f9d09d6fd867c4c422c720246d076 100644 (file)
@@ -271,7 +271,7 @@ pub fn is_separator(c: char) -> bool {
 /// The primary separator of path components for the current platform.
 ///
 /// For example, `/` on Unix and `\` on Windows.
-#[unstable(feature = "main_separator_str", issue = "94071")]
+#[stable(feature = "main_separator_str", since = "CURRENT_RUSTC_VERSION")]
 pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -306,7 +306,7 @@ unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
     // This casts are safe as OsStr is internally a wrapper around [u8] on all
     // platforms.
     //
-    // Note that currently this relies on the special knowledge that libstd has;
+    // Note that currently this relies on the special knowledge that std has;
     // these types are single-element structs but are not marked
     // repr(transparent) or repr(C) which would make these casts not allowable
     // outside std.
@@ -1246,6 +1246,9 @@ pub fn as_path(&self) -> &Path {
     ///   and `path` is not empty, the new path is normalized: all references
     ///   to `.` and `..` are removed.
     ///
+    /// Consider using [`Path::join`] if you need a new `PathBuf` instead of
+    /// using this function on a cloned `PathBuf`.
+    ///
     /// # Examples
     ///
     /// Pushing a relative path extends the existing path:
@@ -1411,7 +1414,8 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
         self.push(file_name);
     }
 
-    /// Updates [`self.extension`] to `extension`.
+    /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+    /// `extension` is empty.
     ///
     /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
     /// returns `true` and updates the extension otherwise.
@@ -1419,6 +1423,20 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
     /// If [`self.extension`] is [`None`], the extension is added; otherwise
     /// it is replaced.
     ///
+    /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+    /// afterwards, not `Some("")`.
+    ///
+    /// # Caveats
+    ///
+    /// The new `extension` may contain dots and will be used in its entirety,
+    /// but only the part after the final dot will be reflected in
+    /// [`self.extension`].
+    ///
+    /// If the file stem contains internal dots and `extension` is empty, part
+    /// of the old file stem will be considered the new [`self.extension`].
+    ///
+    /// See the examples below.
+    ///
     /// [`self.file_name`]: Path::file_name
     /// [`self.extension`]: Path::extension
     ///
@@ -1432,8 +1450,20 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
     /// p.set_extension("force");
     /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
     ///
-    /// p.set_extension("dark_side");
-    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+    /// p.set_extension("dark.side");
+    /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+    ///
+    /// p.set_extension("cookie");
+    /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
index a5a798078eb984ea4772c5e4f6a72ba7ecbd1f0d..2aefd7c513dc8d88421600a69b408a23a5b10aa7 100644 (file)
 
 // Do not `doc(no_inline)` so that they become doc items on their own
 // (no public module for them to be re-exported from).
-#[cfg(not(bootstrap))]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::alloc_error_handler;
-#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
+pub use core::prelude::v1::{
+    alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
 
 #[unstable(feature = "derive_const", issue = "none")]
-#[cfg(not(bootstrap))]
 pub use core::prelude::v1::derive_const;
 
 // Do not `doc(no_inline)` either.
@@ -91,7 +89,6 @@
     issue = "23416",
     reason = "placeholder syntax for type ascription"
 )]
-#[cfg(not(bootstrap))]
 pub use core::prelude::v1::type_ascribe;
 
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
index 17aff342c1599455b2160b43b456bdb8f752246e..62ce2cb33dc55e9df04055a0efc1efe67512e497 100644 (file)
@@ -1038,6 +1038,15 @@ impl fmt::Debug for Command {
     /// Format the program and arguments of a Command for display. Any
     /// non-utf8 data is lossily converted using the utf8 replacement
     /// character.
+    ///
+    /// The default format approximates a shell invocation of the program along with its
+    /// arguments. It does not include most of the other command properties. The output is not guaranteed to work
+    /// (e.g. due to lack of shell-escaping or differences in path resolution)
+    /// On some platforms you can use [the alternate syntax] to show more fields.
+    ///
+    /// Note that the debug implementation is platform-specific.
+    ///
+    /// [the alternate syntax]: fmt#sign0
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.inner.fmt(f)
     }
@@ -2155,18 +2164,11 @@ pub fn id() -> u32 {
 /// to provide similar functionality.
 #[cfg_attr(not(test), lang = "termination")]
 #[stable(feature = "termination_trait_lib", since = "1.61.0")]
-#[rustc_on_unimplemented(
-    on(
-        all(not(bootstrap), cause = "MainFunctionType"),
-        message = "`main` has invalid return type `{Self}`",
-        label = "`main` can only return types that implement `{Termination}`"
-    ),
-    on(
-        bootstrap,
-        message = "`main` has invalid return type `{Self}`",
-        label = "`main` can only return types that implement `{Termination}`"
-    )
-)]
+#[rustc_on_unimplemented(on(
+    cause = "MainFunctionType",
+    message = "`main` has invalid return type `{Self}`",
+    label = "`main` can only return types that implement `{Termination}`"
+))]
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
     /// This status code is returned to the operating system.
index 955ad68916c216ae5fc7493cbca3781309b1e6fe..b4f6cc2dabae39362ac35aca3631f871a2c47a37 100644 (file)
@@ -417,6 +417,100 @@ fn env_empty() {
     assert!(p.is_ok());
 }
 
+#[test]
+#[cfg(not(windows))]
+#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+fn main() {
+    const PIDFD: &'static str =
+        if cfg!(target_os = "linux") { "    create_pidfd: false,\n" } else { "" };
+
+    let mut command = Command::new("some-boring-name");
+
+    assert_eq!(format!("{command:?}"), format!(r#""some-boring-name""#));
+
+    assert_eq!(
+        format!("{command:#?}"),
+        format!(
+            r#"Command {{
+    program: "some-boring-name",
+    args: [
+        "some-boring-name",
+    ],
+{PIDFD}}}"#
+        )
+    );
+
+    command.args(&["1", "2", "3"]);
+
+    assert_eq!(format!("{command:?}"), format!(r#""some-boring-name" "1" "2" "3""#));
+
+    assert_eq!(
+        format!("{command:#?}"),
+        format!(
+            r#"Command {{
+    program: "some-boring-name",
+    args: [
+        "some-boring-name",
+        "1",
+        "2",
+        "3",
+    ],
+{PIDFD}}}"#
+        )
+    );
+
+    crate::os::unix::process::CommandExt::arg0(&mut command, "exciting-name");
+
+    assert_eq!(
+        format!("{command:?}"),
+        format!(r#"["some-boring-name"] "exciting-name" "1" "2" "3""#)
+    );
+
+    assert_eq!(
+        format!("{command:#?}"),
+        format!(
+            r#"Command {{
+    program: "some-boring-name",
+    args: [
+        "exciting-name",
+        "1",
+        "2",
+        "3",
+    ],
+{PIDFD}}}"#
+        )
+    );
+
+    let mut command_with_env_and_cwd = Command::new("boring-name");
+    command_with_env_and_cwd.current_dir("/some/path").env("FOO", "bar");
+    assert_eq!(
+        format!("{command_with_env_and_cwd:?}"),
+        r#"cd "/some/path" && FOO="bar" "boring-name""#
+    );
+    assert_eq!(
+        format!("{command_with_env_and_cwd:#?}"),
+        format!(
+            r#"Command {{
+    program: "boring-name",
+    args: [
+        "boring-name",
+    ],
+    env: CommandEnv {{
+        clear: false,
+        vars: {{
+            "FOO": Some(
+                "bar",
+            ),
+        }},
+    }},
+    cwd: Some(
+        "/some/path",
+    ),
+{PIDFD}}}"#
+        )
+    );
+}
+
 // See issue #91991
 #[test]
 #[cfg(windows)]
index 9c2f0c1dd3eb669fe04fd01c604363bae111ac38..f1eeb75be7c4d805fa009b935a7fd5f809bc5217 100644 (file)
@@ -139,9 +139,9 @@ fn lang_start_internal(
     // mechanism itself.
     //
     // There are a couple of instances where unwinding can begin. First is inside of the
-    // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a
-    // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to
-    // prevent libstd from accidentally introducing a panic to these functions. Another is from
+    // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a
+    // panic is a std implementation bug. A quite likely one too, as there isn't any way to
+    // prevent std from accidentally introducing a panic to these functions. Another is from
     // user code from `main` or, more nefariously, as described in e.g. issue #86030.
     // SAFETY: Only called once during runtime initialization.
     panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
index c8d3289ca4a06986bd81ff1ea97ced5996745bd7..4a15305301d69714badce18702986f90be660e18 100644 (file)
@@ -46,17 +46,15 @@ pub struct LazyLock<T, F = fn() -> T> {
     cell: OnceLock<T>,
     init: Cell<Option<F>>,
 }
-
-impl<T, F> LazyLock<T, F> {
+impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// Creates a new lazy value with the given initializing
     /// function.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub const fn new(f: F) -> LazyLock<T, F> {
         LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
     }
-}
 
-impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// Forces the evaluation of this lazy value and
     /// returns a reference to result. This is equivalent
     /// to the `Deref` impl, but is explicit.
@@ -73,6 +71,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// assert_eq!(LazyLock::force(&lazy), &92);
     /// assert_eq!(&*lazy, &92);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn force(this: &LazyLock<T, F>) -> &T {
         this.cell.get_or_init(|| match this.init.take() {
@@ -85,6 +84,8 @@ pub fn force(this: &LazyLock<T, F>) -> &T {
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
     type Target = T;
+
+    #[inline]
     fn deref(&self) -> &T {
         LazyLock::force(self)
     }
@@ -93,6 +94,7 @@ fn deref(&self) -> &T {
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: Default> Default for LazyLock<T> {
     /// Creates a new lazy value using `Default` as the initializing function.
+    #[inline]
     fn default() -> LazyLock<T> {
         LazyLock::new(T::default)
     }
index f11b66bfca56a90f06993439862464d1ded29d4b..a5d4e25c5962a77885dcc906e5a7e8ae4babbc45 100644 (file)
@@ -136,6 +136,12 @@ fn sync_lazy_poisoning() {
     }
 }
 
+// Check that we can infer `T` from closure's type.
+#[test]
+fn lazy_type_inference() {
+    let _ = LazyCell::new(|| ());
+}
+
 #[test]
 fn is_sync_send() {
     fn assert_traits<T: Send + Sync>() {}
index 4fee8d3e92fc84b58ee1747d095f0bbbcf128d6e..ba20bab87a40dacf90ae63288fe060d12166bb84 100644 (file)
 #[unstable(feature = "once_cell", issue = "74465")]
 pub use self::once_lock::OnceLock;
 
+pub(crate) use self::remutex::{ReentrantMutex, ReentrantMutexGuard};
+
 pub mod mpsc;
 
 mod barrier;
 mod once;
 mod once_lock;
 mod poison;
+mod remutex;
 mod rwlock;
index d0904b4b94cbcc09cb705eca3d42de6ada989ce2..e030c55ce8f6161753b3e517535fef6f49861344 100644 (file)
@@ -136,7 +136,7 @@ pub fn snooze(&self) {
         }
     }
 
-    /// Returns `true` if exponential backoff has completed and blocking the thread is advised.
+    /// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
     #[inline]
     pub fn is_completed(&self) -> bool {
         self.step.get() > YIELD_LIMIT
index 16d1fd2a576b97703ae8483cd01953997d5b6e0d..ed339ca5df669991f3aec60d9e85f6e597918ad6 100644 (file)
@@ -61,8 +61,9 @@ pub struct OnceLock<T> {
 
 impl<T> OnceLock<T> {
     /// Creates a new empty cell.
-    #[unstable(feature = "once_cell", issue = "74465")]
+    #[inline]
     #[must_use]
+    #[unstable(feature = "once_cell", issue = "74465")]
     pub const fn new() -> OnceLock<T> {
         OnceLock {
             once: Once::new(),
@@ -75,6 +76,7 @@ pub const fn new() -> OnceLock<T> {
     ///
     /// Returns `None` if the cell is empty, or being initialized. This
     /// method never blocks.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get(&self) -> Option<&T> {
         if self.is_initialized() {
@@ -88,6 +90,7 @@ pub fn get(&self) -> Option<&T> {
     /// Gets the mutable reference to the underlying value.
     ///
     /// Returns `None` if the cell is empty. This method never blocks.
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_mut(&mut self) -> Option<&mut T> {
         if self.is_initialized() {
@@ -125,6 +128,7 @@ pub fn get_mut(&mut self) -> Option<&mut T> {
     ///     assert_eq!(CELL.get(), Some(&92));
     /// }
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn set(&self, value: T) -> Result<(), T> {
         let mut value = Some(value);
@@ -164,6 +168,7 @@ pub fn set(&self, value: T) -> Result<(), T> {
     /// let value = cell.get_or_init(|| unreachable!());
     /// assert_eq!(value, &92);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_or_init<F>(&self, f: F) -> &T
     where
@@ -203,6 +208,7 @@ pub fn get_or_init<F>(&self, f: F) -> &T
     /// assert_eq!(value, Ok(&92));
     /// assert_eq!(cell.get(), Some(&92))
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
     where
@@ -241,6 +247,7 @@ pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
     /// cell.set("hello".to_string()).unwrap();
     /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn into_inner(mut self) -> Option<T> {
         self.take()
@@ -267,6 +274,7 @@ pub fn into_inner(mut self) -> Option<T> {
     /// assert_eq!(cell.take(), Some("hello".to_string()));
     /// assert_eq!(cell.get(), None);
     /// ```
+    #[inline]
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn take(&mut self) -> Option<T> {
         if self.is_initialized() {
@@ -315,6 +323,7 @@ fn initialize<F, E>(&self, f: F) -> Result<(), E>
     /// # Safety
     ///
     /// The value must be initialized
+    #[inline]
     unsafe fn get_unchecked(&self) -> &T {
         debug_assert!(self.is_initialized());
         (&*self.value.get()).assume_init_ref()
@@ -323,6 +332,7 @@ unsafe fn get_unchecked(&self) -> &T {
     /// # Safety
     ///
     /// The value must be initialized
+    #[inline]
     unsafe fn get_unchecked_mut(&mut self) -> &mut T {
         debug_assert!(self.is_initialized());
         (&mut *self.value.get()).assume_init_mut()
@@ -360,6 +370,7 @@ impl<T> const Default for OnceLock<T> {
     ///     assert_eq!(OnceLock::<()>::new(), OnceLock::default());
     /// }
     /// ```
+    #[inline]
     fn default() -> OnceLock<T> {
         OnceLock::new()
     }
@@ -377,6 +388,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: Clone> Clone for OnceLock<T> {
+    #[inline]
     fn clone(&self) -> OnceLock<T> {
         let cell = Self::new();
         if let Some(value) = self.get() {
@@ -408,6 +420,7 @@ impl<T> From<T> for OnceLock<T> {
     /// Ok(())
     /// # }
     /// ```
+    #[inline]
     fn from(value: T) -> Self {
         let cell = Self::new();
         match cell.set(value) {
@@ -419,6 +432,7 @@ fn from(value: T) -> Self {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T: PartialEq> PartialEq for OnceLock<T> {
+    #[inline]
     fn eq(&self, other: &OnceLock<T>) -> bool {
         self.get() == other.get()
     }
@@ -429,6 +443,7 @@ impl<T: Eq> Eq for OnceLock<T> {}
 
 #[unstable(feature = "once_cell", issue = "74465")]
 unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
+    #[inline]
     fn drop(&mut self) {
         if self.is_initialized() {
             // SAFETY: The cell is initialized and being dropped, so it can't
diff --git a/library/std/src/sync/remutex.rs b/library/std/src/sync/remutex.rs
new file mode 100644 (file)
index 0000000..4c054da
--- /dev/null
@@ -0,0 +1,178 @@
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+use crate::cell::UnsafeCell;
+use crate::ops::Deref;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use crate::sys::locks as sys;
+
+/// A re-entrant mutual exclusion
+///
+/// This mutex will block *other* threads waiting for the lock to become
+/// available. The thread which has already locked the mutex can lock it
+/// multiple times without blocking, preventing a common source of deadlocks.
+///
+/// This is used by stdout().lock() and friends.
+///
+/// ## Implementation details
+///
+/// The 'owner' field tracks which thread has locked the mutex.
+///
+/// We use current_thread_unique_ptr() as the thread identifier,
+/// which is just the address of a thread local variable.
+///
+/// If `owner` is set to the identifier of the current thread,
+/// we assume the mutex is already locked and instead of locking it again,
+/// we increment `lock_count`.
+///
+/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
+/// it reaches zero.
+///
+/// `lock_count` is protected by the mutex and only accessed by the thread that has
+/// locked the mutex, so needs no synchronization.
+///
+/// `owner` can be checked by other threads that want to see if they already
+/// hold the lock, so needs to be atomic. If it compares equal, we're on the
+/// same thread that holds the mutex and memory access can use relaxed ordering
+/// since we're not dealing with multiple threads. If it compares unequal,
+/// synchronization is left to the mutex, making relaxed memory ordering for
+/// the `owner` field fine in all cases.
+pub struct ReentrantMutex<T> {
+    mutex: sys::Mutex,
+    owner: AtomicUsize,
+    lock_count: UnsafeCell<u32>,
+    data: T,
+}
+
+unsafe impl<T: Send> Send for ReentrantMutex<T> {}
+unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
+
+impl<T> UnwindSafe for ReentrantMutex<T> {}
+impl<T> RefUnwindSafe for ReentrantMutex<T> {}
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// Deref implementation.
+///
+/// # Mutability
+///
+/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
+/// because implementation of the trait would violate Rust’s reference aliasing
+/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
+/// guarded data.
+#[must_use = "if unused the ReentrantMutex will immediately unlock"]
+pub struct ReentrantMutexGuard<'a, T: 'a> {
+    lock: &'a ReentrantMutex<T>,
+}
+
+impl<T> !Send for ReentrantMutexGuard<'_, T> {}
+
+impl<T> ReentrantMutex<T> {
+    /// Creates a new reentrant mutex in an unlocked state.
+    pub const fn new(t: T) -> ReentrantMutex<T> {
+        ReentrantMutex {
+            mutex: sys::Mutex::new(),
+            owner: AtomicUsize::new(0),
+            lock_count: UnsafeCell::new(0),
+            data: t,
+        }
+    }
+
+    /// Acquires a mutex, blocking the current thread until it is able to do so.
+    ///
+    /// This function will block the caller until it is available to acquire the mutex.
+    /// Upon returning, the thread is the only thread with the mutex held. When the thread
+    /// calling this method already holds the lock, the call shall succeed without
+    /// blocking.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return failure if the mutex would otherwise be
+    /// acquired.
+    pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
+        let this_thread = current_thread_unique_ptr();
+        // Safety: We only touch lock_count when we own the lock.
+        unsafe {
+            if self.owner.load(Relaxed) == this_thread {
+                self.increment_lock_count();
+            } else {
+                self.mutex.lock();
+                self.owner.store(this_thread, Relaxed);
+                debug_assert_eq!(*self.lock_count.get(), 0);
+                *self.lock_count.get() = 1;
+            }
+        }
+        ReentrantMutexGuard { lock: self }
+    }
+
+    /// Attempts to acquire this lock.
+    ///
+    /// If the lock could not be acquired at this time, then `Err` is returned.
+    /// Otherwise, an RAII guard is returned.
+    ///
+    /// This function does not block.
+    ///
+    /// # Errors
+    ///
+    /// If another user of this mutex panicked while holding the mutex, then
+    /// this call will return failure if the mutex would otherwise be
+    /// acquired.
+    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
+        let this_thread = current_thread_unique_ptr();
+        // Safety: We only touch lock_count when we own the lock.
+        unsafe {
+            if self.owner.load(Relaxed) == this_thread {
+                self.increment_lock_count();
+                Some(ReentrantMutexGuard { lock: self })
+            } else if self.mutex.try_lock() {
+                self.owner.store(this_thread, Relaxed);
+                debug_assert_eq!(*self.lock_count.get(), 0);
+                *self.lock_count.get() = 1;
+                Some(ReentrantMutexGuard { lock: self })
+            } else {
+                None
+            }
+        }
+    }
+
+    unsafe fn increment_lock_count(&self) {
+        *self.lock_count.get() = (*self.lock_count.get())
+            .checked_add(1)
+            .expect("lock count overflow in reentrant mutex");
+    }
+}
+
+impl<T> Deref for ReentrantMutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.lock.data
+    }
+}
+
+impl<T> Drop for ReentrantMutexGuard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        // Safety: We own the lock.
+        unsafe {
+            *self.lock.lock_count.get() -= 1;
+            if *self.lock.lock_count.get() == 0 {
+                self.lock.owner.store(0, Relaxed);
+                self.lock.mutex.unlock();
+            }
+        }
+    }
+}
+
+/// Get an address that is unique per running thread.
+///
+/// This can be used as a non-null usize-sized ID.
+pub fn current_thread_unique_ptr() -> usize {
+    // Use a non-drop type to make sure it's still available during thread destruction.
+    thread_local! { static X: u8 = const { 0 } }
+    X.with(|x| <*const _>::addr(x))
+}
diff --git a/library/std/src/sync/remutex/tests.rs b/library/std/src/sync/remutex/tests.rs
new file mode 100644 (file)
index 0000000..fc55308
--- /dev/null
@@ -0,0 +1,60 @@
+use super::{ReentrantMutex, ReentrantMutexGuard};
+use crate::cell::RefCell;
+use crate::sync::Arc;
+use crate::thread;
+
+#[test]
+fn smoke() {
+    let m = ReentrantMutex::new(());
+    {
+        let a = m.lock();
+        {
+            let b = m.lock();
+            {
+                let c = m.lock();
+                assert_eq!(*c, ());
+            }
+            assert_eq!(*b, ());
+        }
+        assert_eq!(*a, ());
+    }
+}
+
+#[test]
+fn is_mutex() {
+    let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
+    let m2 = m.clone();
+    let lock = m.lock();
+    let child = thread::spawn(move || {
+        let lock = m2.lock();
+        assert_eq!(*lock.borrow(), 4950);
+    });
+    for i in 0..100 {
+        let lock = m.lock();
+        *lock.borrow_mut() += i;
+    }
+    drop(lock);
+    child.join().unwrap();
+}
+
+#[test]
+fn trylock_works() {
+    let m = Arc::new(ReentrantMutex::new(()));
+    let m2 = m.clone();
+    let _lock = m.try_lock();
+    let _lock2 = m.try_lock();
+    thread::spawn(move || {
+        let lock = m2.try_lock();
+        assert!(lock.is_none());
+    })
+    .join()
+    .unwrap();
+    let _lock3 = m.try_lock();
+}
+
+pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
+impl Drop for Answer<'_> {
+    fn drop(&mut self) {
+        *self.0.borrow_mut() = 42;
+    }
+}
index b5b3ad9898edbd0e8cbfb43ffb74f8afd92c1be8..1a9d3d3f12f3cea109c9fa772edbfe128f44afe6 100644 (file)
@@ -2,7 +2,7 @@
 use crate::sync::mpsc::channel;
 use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError};
 use crate::thread;
-use rand::{self, Rng};
+use rand::Rng;
 
 #[derive(Eq, PartialEq, Debug)]
 struct NonCopy(i32);
@@ -28,7 +28,7 @@ fn frob() {
         let tx = tx.clone();
         let r = r.clone();
         thread::spawn(move || {
-            let mut rng = rand::thread_rng();
+            let mut rng = crate::test_helpers::test_rng();
             for _ in 0..M {
                 if rng.gen_bool(1.0 / (N as f64)) {
                     drop(r.write().unwrap());
index c2b3668087225cdc884a28d3a15660974c16b98d..535703be33f06474724a37802df9b6d6fb4f7353 100644 (file)
@@ -119,7 +119,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
 
             let old_lifecycle = inner
                 .lifecycle
-                .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
+                .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::AcqRel);
 
             match old_lifecycle {
                 LIFECYCLE_DETACHED => {
@@ -129,9 +129,9 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
 
                     // In this case, `*p_inner`'s ownership has been moved to
                     // us, and we are responsible for dropping it. The acquire
-                    // ordering is not necessary because the parent thread made
-                    // no memory access needing synchronization since the call
-                    // to `acre_tsk`.
+                    // ordering ensures that the swap operation that wrote
+                    // `LIFECYCLE_DETACHED` happens-before `Box::from_raw(
+                    // p_inner)`.
                     // Safety: See above.
                     let _ = unsafe { Box::from_raw(p_inner) };
 
@@ -151,6 +151,9 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                     // Since the parent might drop `*inner` and terminate us as
                     // soon as it sees `JOIN_FINALIZE`, the release ordering
                     // must be used in the above `swap` call.
+                    //
+                    // To make the task referred to by `parent_tid` visible, we
+                    // must use the acquire ordering in the above `swap` call.
 
                     // [JOINING → JOIN_FINALIZE]
                     // Wake up the parent task.
@@ -218,11 +221,15 @@ pub fn join(self) {
 
         let current_task = current_task as usize;
 
-        match inner.lifecycle.swap(current_task, Ordering::Acquire) {
+        match inner.lifecycle.swap(current_task, Ordering::AcqRel) {
             LIFECYCLE_INIT => {
                 // [INIT → JOINING]
                 // The child task will transition the state to `JOIN_FINALIZE`
                 // and wake us up.
+                //
+                // To make the task referred to by `current_task` visible from
+                // the child task's point of view, we must use the release
+                // ordering in the above `swap` call.
                 loop {
                     expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
                     // To synchronize with the child task's memory accesses to
@@ -267,15 +274,15 @@ fn drop(&mut self) {
         let inner = unsafe { self.p_inner.as_ref() };
 
         // Detach the thread.
-        match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
+        match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::AcqRel) {
             LIFECYCLE_INIT => {
                 // [INIT → DETACHED]
                 // When the time comes, the child will figure out that no
                 // one will ever join it.
                 // The ownership of `*p_inner` is moved to the child thread.
-                // However, the release ordering is not necessary because we
-                // made no memory access needing synchronization since the call
-                // to `acre_tsk`.
+                // The release ordering ensures that the above swap operation on
+                // `lifecycle` happens-before the child thread's
+                // `Box::from_raw(p_inner)`.
             }
             LIFECYCLE_FINISHED => {
                 // [FINISHED → JOINED]
index 63e070207cd707cca701b47e7db0ca5e05b6b4eb..9865a945bad1d17389586da7633767f04eba3991 100644 (file)
@@ -34,7 +34,7 @@
 pub mod stdio;
 pub mod thread;
 pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod time;
 
 mod condvar;
index 579f758c6cc339fe10f5eb65192851c5e48bf15c..1608b8cb642dc858ba13482b2d1f5c72a0ba6bfa 100644 (file)
@@ -65,9 +65,9 @@ pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
 /// execution. The signal is sent once all TLS destructors have finished at
 /// which point no new thread locals should be created.
 pub mod wait_notify {
-    use super::super::thread_parker::Parker;
     use crate::pin::Pin;
     use crate::sync::Arc;
+    use crate::sys_common::thread_parking::Parker;
 
     pub struct Notifier(Arc<Parker>);
 
@@ -87,14 +87,14 @@ impl Waiter {
         /// called, this will return immediately, otherwise the current thread
         /// is blocked until notified.
         pub fn wait(self) {
-            // This is not actually `unsafe`, but it uses the `Parker` API,
-            // which needs `unsafe` on some platforms.
+            // SAFETY:
+            // This is only ever called on one thread.
             unsafe { Pin::new(&*self.0).park() }
         }
     }
 
     pub fn new() -> (Notifier, Waiter) {
-        let inner = Arc::new(Parker::new_internal());
+        let inner = Arc::new(Parker::new());
         (Notifier(inner.clone()), Waiter(inner))
     }
 }
diff --git a/library/std/src/sys/sgx/thread_parker.rs b/library/std/src/sys/sgx/thread_parker.rs
deleted file mode 100644 (file)
index 1c55bcf..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-//! Thread parking based on SGX events.
-
-use super::abi::{thread, usercalls};
-use crate::io::ErrorKind;
-use crate::pin::Pin;
-use crate::ptr::{self, NonNull};
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::time::Duration;
-use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
-
-// The TCS structure must be page-aligned (this is checked by EENTER), so these cannot
-// be valid pointers
-const EMPTY: *mut u8 = ptr::invalid_mut(1);
-const NOTIFIED: *mut u8 = ptr::invalid_mut(2);
-
-pub struct Parker {
-    /// The park state. One of EMPTY, NOTIFIED or a TCS address.
-    /// A state change to NOTIFIED must be done with release ordering
-    /// and be observed with acquire ordering so that operations after
-    /// `thread::park` returns will not occur before the unpark message
-    /// was sent.
-    state: AtomicPtr<u8>,
-}
-
-impl Parker {
-    /// Construct the thread parker. The UNIX parker implementation
-    /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
-        unsafe { parker.write(Parker::new_internal()) }
-    }
-
-    pub(super) fn new_internal() -> Parker {
-        Parker { state: AtomicPtr::new(EMPTY) }
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        if self.state.load(Acquire) != NOTIFIED {
-            let mut prev = EMPTY;
-            loop {
-                // Guard against changing TCS addresses by always setting the state to
-                // the current value.
-                let tcs = thread::current().as_ptr();
-                if self.state.compare_exchange(prev, tcs, Relaxed, Acquire).is_ok() {
-                    let event = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
-                    assert!(event & EV_UNPARK == EV_UNPARK);
-                    prev = tcs;
-                } else {
-                    // The state was definitely changed by another thread at this point.
-                    // The only time this occurs is when the state is changed to NOTIFIED.
-                    // We observed this change with acquire ordering, so we can simply
-                    // change the state to EMPTY with a relaxed store.
-                    break;
-                }
-            }
-        }
-
-        // At this point, the token was definately read with acquire ordering,
-        // so this can be a relaxed store.
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
-        let tcs = thread::current().as_ptr();
-
-        if self.state.load(Acquire) != NOTIFIED {
-            if self.state.compare_exchange(EMPTY, tcs, Relaxed, Acquire).is_ok() {
-                match usercalls::wait(EV_UNPARK, timeout) {
-                    Ok(event) => assert!(event & EV_UNPARK == EV_UNPARK),
-                    Err(e) => {
-                        assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
-                    }
-                }
-
-                // Swap to provide acquire ordering even if the timeout occurred
-                // before the token was set. This situation can result in spurious
-                // wakeups on the next call to `park_timeout`, but it is better to let
-                // those be handled by the user than do some perhaps unnecessary, but
-                // always expensive guarding.
-                self.state.swap(EMPTY, Acquire);
-                return;
-            }
-        }
-
-        // The token was already read with `acquire` ordering, this can be a store.
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-
-        if !matches!(state, EMPTY | NOTIFIED) {
-            // There is a thread waiting, wake it up.
-            let tcs = NonNull::new(state).unwrap();
-            // This will fail if the thread has already terminated or its TCS is destroyed
-            // by the time the signal is sent, but that is fine. If another thread receives
-            // the same TCS, it will receive this notification as a spurious wakeup, but
-            // all users of `wait` should and (internally) do guard against those where
-            // necessary.
-            let _ = usercalls::send(EV_UNPARK, Some(tcs));
-        }
-    }
-}
diff --git a/library/std/src/sys/sgx/thread_parking.rs b/library/std/src/sys/sgx/thread_parking.rs
new file mode 100644 (file)
index 0000000..0006cd4
--- /dev/null
@@ -0,0 +1,23 @@
+use super::abi::usercalls;
+use crate::io::ErrorKind;
+use crate::time::Duration;
+use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
+
+pub type ThreadId = fortanix_sgx_abi::Tcs;
+
+pub use super::abi::thread::current;
+
+pub fn park(_hint: usize) {
+    usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
+}
+
+pub fn park_timeout(dur: Duration, _hint: usize) {
+    let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
+    if let Err(e) = usercalls::wait(EV_UNPARK, timeout) {
+        assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
+    }
+}
+
+pub fn unpark(tid: ThreadId, _hint: usize) {
+    let _ = usercalls::send(EV_UNPARK, Some(tid));
+}
index 73ff10ab8a221ccad212d9f231caa13fbc5b333d..0f704994f550ab5810857a8ca26179ba26ea561f 100644 (file)
@@ -1,7 +1,7 @@
 //! Android ABI-compatibility module
 //!
-//! The ABI of Android has changed quite a bit over time, and libstd attempts to
-//! be both forwards and backwards compatible as much as possible. We want to
+//! The ABI of Android has changed quite a bit over time, and std attempts to be
+//! both forwards and backwards compatible as much as possible. We want to
 //! always work with the most recent version of Android, but we also want to
 //! work with older versions of Android for whenever projects need to.
 //!
index 83a43b6ee2697ca14c6e8e75c8d3b4788c32cd59..30a96be14300a8f8c07fb2f81cf52af12e640ef6 100644 (file)
@@ -40,7 +40,7 @@
 pub mod thread;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod time;
 
 #[cfg(target_os = "espidf")]
@@ -164,7 +164,7 @@ unsafe fn sanitize_standard_fds() {
     unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
         #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
         {
-            // We don't want to add this as a public type to libstd, nor do we
+            // We don't want to add this as a public type to std, nor do we
             // want to `include!` a file from the compiler (which would break
             // Miri and xargo for example), so we choose to duplicate these
             // constants from `compiler/rustc_session/src/config/sigpipe.rs`.
@@ -184,12 +184,7 @@ mod sigpipe {
                 sigpipe::SIG_DFL => (true, Some(libc::SIG_DFL)),
                 _ => unreachable!(),
             };
-            // The bootstrap compiler doesn't know about sigpipe::DEFAULT, and always passes in
-            // SIG_IGN. This causes some tests to fail because they expect SIGPIPE to be reset to
-            // default on process spawning (which doesn't happen if #[unix_sigpipe] is specified).
-            // Since we can't differentiate between the cases here, treat SIG_IGN as DEFAULT
-            // unconditionally.
-            if sigpipe_attr_specified && !(cfg!(bootstrap) && sigpipe == sigpipe::SIG_IGN) {
+            if sigpipe_attr_specified {
                 UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
             }
             if let Some(handler) = handler {
index b84bf8f9264a405821f6453296c0d43de65f42f4..c86f80972a69de412dd1ac0a26561353df056f1a 100644 (file)
@@ -512,7 +512,7 @@ unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
 // A workaround for this bug is to call the res_init libc function, to clear
 // the cached configs. Unfortunately, while we believe glibc's implementation
 // of res_init is thread-safe, we know that other implementations are not
-// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// (https://github.com/rust-lang/rust/issues/43592). Code here in std could
 // try to synchronize its res_init calls with a Mutex, but that wouldn't
 // protect programs that call into libc in other ways. So instead of calling
 // res_init unconditionally, we call it only when we detect we're linking
index 848adca78c076f99fdec48c553410fe7a753c549..afd03d79c0ba6cef9747d003c760adfc07f2c721 100644 (file)
@@ -144,6 +144,7 @@ pub enum ChildStdio {
     Null,
 }
 
+#[derive(Debug)]
 pub enum Stdio {
     Inherit,
     Null,
@@ -510,16 +511,68 @@ pub fn fd(&self) -> Option<c_int> {
 }
 
 impl fmt::Debug for Command {
+    // show all attributes but `self.closures` which does not implement `Debug`
+    // and `self.argv` which is not useful for debugging
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.program != self.args[0] {
-            write!(f, "[{:?}] ", self.program)?;
-        }
-        write!(f, "{:?}", self.args[0])?;
+        if f.alternate() {
+            let mut debug_command = f.debug_struct("Command");
+            debug_command.field("program", &self.program).field("args", &self.args);
+            if !self.env.is_unchanged() {
+                debug_command.field("env", &self.env);
+            }
+
+            if self.cwd.is_some() {
+                debug_command.field("cwd", &self.cwd);
+            }
+            if self.uid.is_some() {
+                debug_command.field("uid", &self.uid);
+            }
+            if self.gid.is_some() {
+                debug_command.field("gid", &self.gid);
+            }
+
+            if self.groups.is_some() {
+                debug_command.field("groups", &self.groups);
+            }
+
+            if self.stdin.is_some() {
+                debug_command.field("stdin", &self.stdin);
+            }
+            if self.stdout.is_some() {
+                debug_command.field("stdout", &self.stdout);
+            }
+            if self.stderr.is_some() {
+                debug_command.field("stderr", &self.stderr);
+            }
+            if self.pgroup.is_some() {
+                debug_command.field("pgroup", &self.pgroup);
+            }
+
+            #[cfg(target_os = "linux")]
+            {
+                debug_command.field("create_pidfd", &self.create_pidfd);
+            }
 
-        for arg in &self.args[1..] {
-            write!(f, " {:?}", arg)?;
+            debug_command.finish()
+        } else {
+            if let Some(ref cwd) = self.cwd {
+                write!(f, "cd {cwd:?} && ")?;
+            }
+            for (key, value_opt) in self.get_envs() {
+                if let Some(value) = value_opt {
+                    write!(f, "{}={value:?} ", key.to_string_lossy())?;
+                }
+            }
+            if self.program != self.args[0] {
+                write!(f, "[{:?}] ", self.program)?;
+            }
+            write!(f, "{:?}", self.args[0])?;
+
+            for arg in &self.args[1..] {
+                write!(f, " {:?}", arg)?;
+            }
+            Ok(())
         }
-        Ok(())
     }
 }
 
index d847f2775ab7611bfcc249c32763179683f0cb04..b251949bda207e1bf0fcfa99750e7311f4412dce 100644 (file)
@@ -505,7 +505,7 @@ fn quota_v2(group_path: PathBuf) -> usize {
                     let limit = raw_quota.next()?;
                     let period = raw_quota.next()?;
                     match (limit.parse::<usize>(), period.parse::<usize>()) {
-                        (Ok(limit), Ok(period)) => {
+                        (Ok(limit), Ok(period)) if period > 0 => {
                             quota = quota.min(limit / period);
                         }
                         _ => {}
@@ -565,7 +565,7 @@ fn quota_v1(group_path: PathBuf) -> usize {
                 let period = parse_file("cpu.cfs_period_us");
 
                 match (limit, period) {
-                    (Some(limit), Some(period)) => quota = quota.min(limit / period),
+                    (Some(limit), Some(period)) if period > 0 => quota = quota.min(limit / period),
                     _ => {}
                 }
 
diff --git a/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parker/darwin.rs
deleted file mode 100644 (file)
index 2f5356f..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-//! Thread parking for Darwin-based systems.
-//!
-//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they
-//! cannot be used in `std` because they are non-public (their use will lead to
-//! rejection from the App Store) and because they are only available starting
-//! with macOS version 10.12, even though the minimum target version is 10.7.
-//!
-//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
-//! supports semaphores, which allow us to implement the behaviour we need with
-//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore
-//! provided by libdispatch, as the underlying Mach semaphore is only dubiously
-//! public.
-
-use crate::pin::Pin;
-use crate::sync::atomic::{
-    AtomicI8,
-    Ordering::{Acquire, Release},
-};
-use crate::time::Duration;
-
-type dispatch_semaphore_t = *mut crate::ffi::c_void;
-type dispatch_time_t = u64;
-
-const DISPATCH_TIME_NOW: dispatch_time_t = 0;
-const DISPATCH_TIME_FOREVER: dispatch_time_t = !0;
-
-// Contained in libSystem.dylib, which is linked by default.
-extern "C" {
-    fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t;
-    fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t;
-    fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize;
-    fn dispatch_semaphore_signal(dsema: dispatch_semaphore_t) -> isize;
-    fn dispatch_release(object: *mut crate::ffi::c_void);
-}
-
-const EMPTY: i8 = 0;
-const NOTIFIED: i8 = 1;
-const PARKED: i8 = -1;
-
-pub struct Parker {
-    semaphore: dispatch_semaphore_t,
-    state: AtomicI8,
-}
-
-unsafe impl Sync for Parker {}
-unsafe impl Send for Parker {}
-
-impl Parker {
-    pub unsafe fn new(parker: *mut Parker) {
-        let semaphore = dispatch_semaphore_create(0);
-        assert!(
-            !semaphore.is_null(),
-            "failed to create dispatch semaphore for thread synchronization"
-        );
-        parker.write(Parker { semaphore, state: AtomicI8::new(EMPTY) })
-    }
-
-    // Does not need `Pin`, but other implementation do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // The semaphore counter must be zero at this point, because unparking
-        // threads will not actually increase it until we signalled that we
-        // are waiting.
-
-        // Change NOTIFIED to EMPTY and EMPTY to PARKED.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-
-        // Another thread may increase the semaphore counter from this point on.
-        // If it is faster than us, we will decrement it again immediately below.
-        // If we are faster, we wait.
-
-        // Ensure that the semaphore counter has actually been decremented, even
-        // if the call timed out for some reason.
-        while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
-
-        // At this point, the semaphore counter is zero again.
-
-        // We were definitely woken up, so we don't need to check the state.
-        // Still, we need to reset the state using a swap to observe the state
-        // change with acquire ordering.
-        self.state.swap(EMPTY, Acquire);
-    }
-
-    // Does not need `Pin`, but other implementation do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-
-        let nanos = dur.as_nanos().try_into().unwrap_or(i64::MAX);
-        let timeout = dispatch_time(DISPATCH_TIME_NOW, nanos);
-
-        let timeout = dispatch_semaphore_wait(self.semaphore, timeout) != 0;
-
-        let state = self.state.swap(EMPTY, Acquire);
-        if state == NOTIFIED && timeout {
-            // If the state was NOTIFIED but semaphore_wait returned without
-            // decrementing the count because of a timeout, it means another
-            // thread is about to call semaphore_signal. We must wait for that
-            // to happen to ensure the semaphore count is reset.
-            while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
-        } else {
-            // Either a timeout occurred and we reset the state before any thread
-            // tried to wake us up, or we were woken up and reset the state,
-            // making sure to observe the state change with acquire ordering.
-            // Either way, the semaphore counter is now zero again.
-        }
-    }
-
-    // Does not need `Pin`, but other implementation do.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-        if state == PARKED {
-            unsafe {
-                dispatch_semaphore_signal(self.semaphore);
-            }
-        }
-    }
-}
-
-impl Drop for Parker {
-    fn drop(&mut self) {
-        // SAFETY:
-        // We always ensure that the semaphore count is reset, so this will
-        // never cause an exception.
-        unsafe {
-            dispatch_release(self.semaphore);
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs
deleted file mode 100644 (file)
index 35f1e68..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-//! Thread parking on systems without futex support.
-
-#![cfg(not(any(
-    target_os = "linux",
-    target_os = "android",
-    all(target_os = "emscripten", target_feature = "atomics"),
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "dragonfly",
-    target_os = "fuchsia",
-)))]
-
-cfg_if::cfg_if! {
-    if #[cfg(all(
-        any(
-            target_os = "macos",
-            target_os = "ios",
-            target_os = "watchos",
-            target_os = "tvos",
-        ),
-        not(miri),
-    ))] {
-        mod darwin;
-        pub use darwin::Parker;
-    } else if #[cfg(target_os = "netbsd")] {
-        mod netbsd;
-        pub use netbsd::Parker;
-    } else {
-        mod pthread;
-        pub use pthread::Parker;
-    }
-}
diff --git a/library/std/src/sys/unix/thread_parker/netbsd.rs b/library/std/src/sys/unix/thread_parker/netbsd.rs
deleted file mode 100644 (file)
index 7657605..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-use crate::ffi::{c_int, c_void};
-use crate::pin::Pin;
-use crate::ptr::{null, null_mut};
-use crate::sync::atomic::{
-    AtomicU64,
-    Ordering::{Acquire, Relaxed, Release},
-};
-use crate::time::Duration;
-use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
-
-extern "C" {
-    fn ___lwp_park60(
-        clock_id: clockid_t,
-        flags: c_int,
-        ts: *mut timespec,
-        unpark: lwpid_t,
-        hint: *const c_void,
-        unparkhint: *const c_void,
-    ) -> c_int;
-    fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
-}
-
-/// The thread is not parked and the token is not available.
-///
-/// Zero cannot be a valid LWP id, since it is used as empty value for the unpark
-/// argument in _lwp_park.
-const EMPTY: u64 = 0;
-/// The token is available. Do not park anymore.
-const NOTIFIED: u64 = u64::MAX;
-
-pub struct Parker {
-    /// The parker state. Contains either one of the two state values above or the LWP
-    /// id of the parked thread.
-    state: AtomicU64,
-}
-
-impl Parker {
-    pub unsafe fn new(parker: *mut Parker) {
-        parker.write(Parker { state: AtomicU64::new(EMPTY) })
-    }
-
-    // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // If the token has already been made available, we can skip
-        // a bit of work, so check for it here.
-        if self.state.load(Acquire) != NOTIFIED {
-            let parked = _lwp_self() as u64;
-            let hint = self.state.as_mut_ptr().cast();
-            if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
-                // Loop to guard against spurious wakeups.
-                loop {
-                    ___lwp_park60(0, 0, null_mut(), 0, hint, null());
-                    if self.state.load(Acquire) == NOTIFIED {
-                        break;
-                    }
-                }
-            }
-        }
-
-        // At this point, the change to NOTIFIED has always been observed with acquire
-        // ordering, so we can just use a relaxed store here (instead of a swap).
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // Does not actually need `unsafe` or `Pin`, but the pthread implementation does.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        if self.state.load(Acquire) != NOTIFIED {
-            let parked = _lwp_self() as u64;
-            let hint = self.state.as_mut_ptr().cast();
-            let mut timeout = timespec {
-                // Saturate so that the operation will definitely time out
-                // (even if it is after the heat death of the universe).
-                tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
-                tv_nsec: dur.subsec_nanos().into(),
-            };
-
-            if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() {
-                // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
-                // above.
-                ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, hint, null());
-                // Use a swap to get acquire ordering even if the token was set after
-                // the timeout occurred.
-                self.state.swap(EMPTY, Acquire);
-                return;
-            }
-        }
-
-        self.state.store(EMPTY, Relaxed);
-    }
-
-    // Does not actually need `Pin`, but the pthread implementation does.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-        if !matches!(state, EMPTY | NOTIFIED) {
-            let lwp = state as lwpid_t;
-            let hint = self.state.as_mut_ptr().cast();
-
-            // If the parking thread terminated and did not actually park, this will
-            // probably return an error, which is OK. In the worst case, another
-            // thread has received the same LWP id. It will then receive a spurious
-            // wakeup, but those are allowable per the API contract. The same reasoning
-            // applies if a timeout occurred before this call, but the state was not
-            // yet reset.
-
-            // SAFETY:
-            // The syscall has no invariants to hold. Only unsafe because it is an
-            // extern function.
-            unsafe {
-                _lwp_unpark(lwp, hint);
-            }
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/thread_parker/pthread.rs b/library/std/src/sys/unix/thread_parker/pthread.rs
deleted file mode 100644 (file)
index c400c77..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-//! Thread parking without `futex` using the `pthread` synchronization primitives.
-
-use crate::cell::UnsafeCell;
-use crate::marker::PhantomPinned;
-use crate::pin::Pin;
-use crate::ptr::addr_of_mut;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sys::time::TIMESPEC_MAX;
-use crate::time::Duration;
-
-const EMPTY: usize = 0;
-const PARKED: usize = 1;
-const NOTIFIED: usize = 2;
-
-unsafe fn lock(lock: *mut libc::pthread_mutex_t) {
-    let r = libc::pthread_mutex_lock(lock);
-    debug_assert_eq!(r, 0);
-}
-
-unsafe fn unlock(lock: *mut libc::pthread_mutex_t) {
-    let r = libc::pthread_mutex_unlock(lock);
-    debug_assert_eq!(r, 0);
-}
-
-unsafe fn notify_one(cond: *mut libc::pthread_cond_t) {
-    let r = libc::pthread_cond_signal(cond);
-    debug_assert_eq!(r, 0);
-}
-
-unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) {
-    let r = libc::pthread_cond_wait(cond, lock);
-    debug_assert_eq!(r, 0);
-}
-
-unsafe fn wait_timeout(
-    cond: *mut libc::pthread_cond_t,
-    lock: *mut libc::pthread_mutex_t,
-    dur: Duration,
-) {
-    // Use the system clock on systems that do not support pthread_condattr_setclock.
-    // This unfortunately results in problems when the system time changes.
-    #[cfg(any(
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "watchos",
-        target_os = "espidf"
-    ))]
-    let (now, dur) = {
-        use crate::cmp::min;
-        use crate::sys::time::SystemTime;
-
-        // OSX implementation of `pthread_cond_timedwait` is buggy
-        // with super long durations. When duration is greater than
-        // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
-        // in macOS Sierra return error 316.
-        //
-        // This program demonstrates the issue:
-        // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
-        //
-        // To work around this issue, and possible bugs of other OSes, timeout
-        // is clamped to 1000 years, which is allowable per the API of `park_timeout`
-        // because of spurious wakeups.
-        let dur = min(dur, Duration::from_secs(1000 * 365 * 86400));
-        let now = SystemTime::now().t;
-        (now, dur)
-    };
-    // Use the monotonic clock on other systems.
-    #[cfg(not(any(
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "watchos",
-        target_os = "espidf"
-    )))]
-    let (now, dur) = {
-        use crate::sys::time::Timespec;
-
-        (Timespec::now(libc::CLOCK_MONOTONIC), dur)
-    };
-
-    let timeout =
-        now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
-    let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
-    debug_assert!(r == libc::ETIMEDOUT || r == 0);
-}
-
-pub struct Parker {
-    state: AtomicUsize,
-    lock: UnsafeCell<libc::pthread_mutex_t>,
-    cvar: UnsafeCell<libc::pthread_cond_t>,
-    // The `pthread` primitives require a stable address, so make this struct `!Unpin`.
-    _pinned: PhantomPinned,
-}
-
-impl Parker {
-    /// Construct the UNIX parker in-place.
-    ///
-    /// # Safety
-    /// The constructed parker must never be moved.
-    pub unsafe fn new(parker: *mut Parker) {
-        // Use the default mutex implementation to allow for simpler initialization.
-        // This could lead to undefined behaviour when deadlocking. This is avoided
-        // by not deadlocking. Note in particular the unlocking operation before any
-        // panic, as code after the panic could try to park again.
-        addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY));
-        addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
-
-        cfg_if::cfg_if! {
-            if #[cfg(any(
-                target_os = "macos",
-                target_os = "ios",
-                target_os = "watchos",
-                target_os = "l4re",
-                target_os = "android",
-                target_os = "redox"
-            ))] {
-                addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
-            } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
-                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null());
-                assert_eq!(r, 0);
-            } else {
-                use crate::mem::MaybeUninit;
-                let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
-                let r = libc::pthread_condattr_init(attr.as_mut_ptr());
-                assert_eq!(r, 0);
-                let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
-                assert_eq!(r, 0);
-                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr());
-                assert_eq!(r, 0);
-                let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
-                assert_eq!(r, 0);
-            }
-        }
-    }
-
-    // This implementation doesn't require `unsafe`, but other implementations
-    // may assume this is only called by the thread that owns the Parker.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // If we were previously notified then we consume this notification and
-        // return quickly.
-        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-            return;
-        }
-
-        // Otherwise we need to coordinate going to sleep
-        lock(self.lock.get());
-        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-            Ok(_) => {}
-            Err(NOTIFIED) => {
-                // We must read here, even though we know it will be `NOTIFIED`.
-                // This is because `unpark` may have been called again since we read
-                // `NOTIFIED` in the `compare_exchange` above. We must perform an
-                // acquire operation that synchronizes with that `unpark` to observe
-                // any writes it made before the call to unpark. To do that we must
-                // read from the write it made to `state`.
-                let old = self.state.swap(EMPTY, SeqCst);
-
-                unlock(self.lock.get());
-
-                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-                return;
-            } // should consume this notification, so prohibit spurious wakeups in next park.
-            Err(_) => {
-                unlock(self.lock.get());
-
-                panic!("inconsistent park state")
-            }
-        }
-
-        loop {
-            wait(self.cvar.get(), self.lock.get());
-
-            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
-                Ok(_) => break, // got a notification
-                Err(_) => {}    // spurious wakeup, go back to sleep
-            }
-        }
-
-        unlock(self.lock.get());
-    }
-
-    // This implementation doesn't require `unsafe`, but other implementations
-    // may assume this is only called by the thread that owns the Parker. Use
-    // `Pin` to guarantee a stable address for the mutex and condition variable.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        // Like `park` above we have a fast path for an already-notified thread, and
-        // afterwards we start coordinating for a sleep.
-        // return quickly.
-        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-            return;
-        }
-
-        lock(self.lock.get());
-        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-            Ok(_) => {}
-            Err(NOTIFIED) => {
-                // We must read again here, see `park`.
-                let old = self.state.swap(EMPTY, SeqCst);
-                unlock(self.lock.get());
-
-                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-                return;
-            } // should consume this notification, so prohibit spurious wakeups in next park.
-            Err(_) => {
-                unlock(self.lock.get());
-                panic!("inconsistent park_timeout state")
-            }
-        }
-
-        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
-        // from a notification we just want to unconditionally set the state back to
-        // empty, either consuming a notification or un-flagging ourselves as
-        // parked.
-        wait_timeout(self.cvar.get(), self.lock.get(), dur);
-
-        match self.state.swap(EMPTY, SeqCst) {
-            NOTIFIED => unlock(self.lock.get()), // got a notification, hurray!
-            PARKED => unlock(self.lock.get()),   // no notification, alas
-            n => {
-                unlock(self.lock.get());
-                panic!("inconsistent park_timeout state: {n}")
-            }
-        }
-    }
-
-    pub fn unpark(self: Pin<&Self>) {
-        // To ensure the unparked thread will observe any writes we made
-        // before this call, we must perform a release operation that `park`
-        // can synchronize with. To do that we must write `NOTIFIED` even if
-        // `state` is already `NOTIFIED`. That is why this must be a swap
-        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
-        // on failure.
-        match self.state.swap(NOTIFIED, SeqCst) {
-            EMPTY => return,    // no one was waiting
-            NOTIFIED => return, // already unparked
-            PARKED => {}        // gotta go wake someone up
-            _ => panic!("inconsistent state in unpark"),
-        }
-
-        // There is a period between when the parked thread sets `state` to
-        // `PARKED` (or last checked `state` in the case of a spurious wake
-        // up) and when it actually waits on `cvar`. If we were to notify
-        // during this period it would be ignored and then when the parked
-        // thread went to sleep it would never wake up. Fortunately, it has
-        // `lock` locked at this stage so we can acquire `lock` to wait until
-        // it is ready to receive the notification.
-        //
-        // Releasing `lock` before the call to `notify_one` means that when the
-        // parked thread wakes it doesn't get woken only to have to wait for us
-        // to release `lock`.
-        unsafe {
-            lock(self.lock.get());
-            unlock(self.lock.get());
-            notify_one(self.cvar.get());
-        }
-    }
-}
-
-impl Drop for Parker {
-    fn drop(&mut self) {
-        unsafe {
-            libc::pthread_cond_destroy(self.cvar.get_mut());
-            libc::pthread_mutex_destroy(self.lock.get_mut());
-        }
-    }
-}
-
-unsafe impl Sync for Parker {}
-unsafe impl Send for Parker {}
diff --git a/library/std/src/sys/unix/thread_parking/darwin.rs b/library/std/src/sys/unix/thread_parking/darwin.rs
new file mode 100644 (file)
index 0000000..b709fad
--- /dev/null
@@ -0,0 +1,131 @@
+//! Thread parking for Darwin-based systems.
+//!
+//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they
+//! cannot be used in `std` because they are non-public (their use will lead to
+//! rejection from the App Store) and because they are only available starting
+//! with macOS version 10.12, even though the minimum target version is 10.7.
+//!
+//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
+//! supports semaphores, which allow us to implement the behaviour we need with
+//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore
+//! provided by libdispatch, as the underlying Mach semaphore is only dubiously
+//! public.
+
+use crate::pin::Pin;
+use crate::sync::atomic::{
+    AtomicI8,
+    Ordering::{Acquire, Release},
+};
+use crate::time::Duration;
+
+type dispatch_semaphore_t = *mut crate::ffi::c_void;
+type dispatch_time_t = u64;
+
+const DISPATCH_TIME_NOW: dispatch_time_t = 0;
+const DISPATCH_TIME_FOREVER: dispatch_time_t = !0;
+
+// Contained in libSystem.dylib, which is linked by default.
+extern "C" {
+    fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t;
+    fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t;
+    fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize;
+    fn dispatch_semaphore_signal(dsema: dispatch_semaphore_t) -> isize;
+    fn dispatch_release(object: *mut crate::ffi::c_void);
+}
+
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+const PARKED: i8 = -1;
+
+pub struct Parker {
+    semaphore: dispatch_semaphore_t,
+    state: AtomicI8,
+}
+
+unsafe impl Sync for Parker {}
+unsafe impl Send for Parker {}
+
+impl Parker {
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        let semaphore = dispatch_semaphore_create(0);
+        assert!(
+            !semaphore.is_null(),
+            "failed to create dispatch semaphore for thread synchronization"
+        );
+        parker.write(Parker { semaphore, state: AtomicI8::new(EMPTY) })
+    }
+
+    // Does not need `Pin`, but other implementation do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // The semaphore counter must be zero at this point, because unparking
+        // threads will not actually increase it until we signalled that we
+        // are waiting.
+
+        // Change NOTIFIED to EMPTY and EMPTY to PARKED.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+
+        // Another thread may increase the semaphore counter from this point on.
+        // If it is faster than us, we will decrement it again immediately below.
+        // If we are faster, we wait.
+
+        // Ensure that the semaphore counter has actually been decremented, even
+        // if the call timed out for some reason.
+        while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
+
+        // At this point, the semaphore counter is zero again.
+
+        // We were definitely woken up, so we don't need to check the state.
+        // Still, we need to reset the state using a swap to observe the state
+        // change with acquire ordering.
+        self.state.swap(EMPTY, Acquire);
+    }
+
+    // Does not need `Pin`, but other implementation do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+
+        let nanos = dur.as_nanos().try_into().unwrap_or(i64::MAX);
+        let timeout = dispatch_time(DISPATCH_TIME_NOW, nanos);
+
+        let timeout = dispatch_semaphore_wait(self.semaphore, timeout) != 0;
+
+        let state = self.state.swap(EMPTY, Acquire);
+        if state == NOTIFIED && timeout {
+            // If the state was NOTIFIED but semaphore_wait returned without
+            // decrementing the count because of a timeout, it means another
+            // thread is about to call semaphore_signal. We must wait for that
+            // to happen to ensure the semaphore count is reset.
+            while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
+        } else {
+            // Either a timeout occurred and we reset the state before any thread
+            // tried to wake us up, or we were woken up and reset the state,
+            // making sure to observe the state change with acquire ordering.
+            // Either way, the semaphore counter is now zero again.
+        }
+    }
+
+    // Does not need `Pin`, but other implementation do.
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+        if state == PARKED {
+            unsafe {
+                dispatch_semaphore_signal(self.semaphore);
+            }
+        }
+    }
+}
+
+impl Drop for Parker {
+    fn drop(&mut self) {
+        // SAFETY:
+        // We always ensure that the semaphore count is reset, so this will
+        // never cause an exception.
+        unsafe {
+            dispatch_release(self.semaphore);
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/thread_parking/mod.rs b/library/std/src/sys/unix/thread_parking/mod.rs
new file mode 100644 (file)
index 0000000..185333c
--- /dev/null
@@ -0,0 +1,32 @@
+//! Thread parking on systems without futex support.
+
+#![cfg(not(any(
+    target_os = "linux",
+    target_os = "android",
+    all(target_os = "emscripten", target_feature = "atomics"),
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "dragonfly",
+    target_os = "fuchsia",
+)))]
+
+cfg_if::cfg_if! {
+    if #[cfg(all(
+        any(
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "watchos",
+            target_os = "tvos",
+        ),
+        not(miri),
+    ))] {
+        mod darwin;
+        pub use darwin::Parker;
+    } else if #[cfg(target_os = "netbsd")] {
+        mod netbsd;
+        pub use netbsd::{current, park, park_timeout, unpark, ThreadId};
+    } else {
+        mod pthread;
+        pub use pthread::Parker;
+    }
+}
diff --git a/library/std/src/sys/unix/thread_parking/netbsd.rs b/library/std/src/sys/unix/thread_parking/netbsd.rs
new file mode 100644 (file)
index 0000000..3be0812
--- /dev/null
@@ -0,0 +1,52 @@
+use crate::ffi::{c_int, c_void};
+use crate::ptr;
+use crate::time::Duration;
+use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC};
+
+extern "C" {
+    fn ___lwp_park60(
+        clock_id: clockid_t,
+        flags: c_int,
+        ts: *mut timespec,
+        unpark: lwpid_t,
+        hint: *const c_void,
+        unparkhint: *const c_void,
+    ) -> c_int;
+    fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
+}
+
+pub type ThreadId = lwpid_t;
+
+#[inline]
+pub fn current() -> ThreadId {
+    unsafe { _lwp_self() }
+}
+
+#[inline]
+pub fn park(hint: usize) {
+    unsafe {
+        ___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::invalid(hint), ptr::null());
+    }
+}
+
+pub fn park_timeout(dur: Duration, hint: usize) {
+    let mut timeout = timespec {
+        // Saturate so that the operation will definitely time out
+        // (even if it is after the heat death of the universe).
+        tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX),
+        tv_nsec: dur.subsec_nanos().into(),
+    };
+
+    // Timeout needs to be mutable since it is modified on NetBSD 9.0 and
+    // above.
+    unsafe {
+        ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, ptr::invalid(hint), ptr::null());
+    }
+}
+
+#[inline]
+pub fn unpark(tid: ThreadId, hint: usize) {
+    unsafe {
+        _lwp_unpark(tid, ptr::invalid(hint));
+    }
+}
diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs
new file mode 100644 (file)
index 0000000..082d25e
--- /dev/null
@@ -0,0 +1,271 @@
+//! Thread parking without `futex` using the `pthread` synchronization primitives.
+
+use crate::cell::UnsafeCell;
+use crate::marker::PhantomPinned;
+use crate::pin::Pin;
+use crate::ptr::addr_of_mut;
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sys::time::TIMESPEC_MAX;
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+unsafe fn lock(lock: *mut libc::pthread_mutex_t) {
+    let r = libc::pthread_mutex_lock(lock);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn unlock(lock: *mut libc::pthread_mutex_t) {
+    let r = libc::pthread_mutex_unlock(lock);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn notify_one(cond: *mut libc::pthread_cond_t) {
+    let r = libc::pthread_cond_signal(cond);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t) {
+    let r = libc::pthread_cond_wait(cond, lock);
+    debug_assert_eq!(r, 0);
+}
+
+unsafe fn wait_timeout(
+    cond: *mut libc::pthread_cond_t,
+    lock: *mut libc::pthread_mutex_t,
+    dur: Duration,
+) {
+    // Use the system clock on systems that do not support pthread_condattr_setclock.
+    // This unfortunately results in problems when the system time changes.
+    #[cfg(any(
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "watchos",
+        target_os = "espidf",
+        target_os = "horizon",
+    ))]
+    let (now, dur) = {
+        use crate::cmp::min;
+        use crate::sys::time::SystemTime;
+
+        // OSX implementation of `pthread_cond_timedwait` is buggy
+        // with super long durations. When duration is greater than
+        // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
+        // in macOS Sierra return error 316.
+        //
+        // This program demonstrates the issue:
+        // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
+        //
+        // To work around this issue, and possible bugs of other OSes, timeout
+        // is clamped to 1000 years, which is allowable per the API of `park_timeout`
+        // because of spurious wakeups.
+        let dur = min(dur, Duration::from_secs(1000 * 365 * 86400));
+        let now = SystemTime::now().t;
+        (now, dur)
+    };
+    // Use the monotonic clock on other systems.
+    #[cfg(not(any(
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "watchos",
+        target_os = "espidf",
+        target_os = "horizon",
+    )))]
+    let (now, dur) = {
+        use crate::sys::time::Timespec;
+
+        (Timespec::now(libc::CLOCK_MONOTONIC), dur)
+    };
+
+    let timeout =
+        now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
+    let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
+    debug_assert!(r == libc::ETIMEDOUT || r == 0);
+}
+
+pub struct Parker {
+    state: AtomicUsize,
+    lock: UnsafeCell<libc::pthread_mutex_t>,
+    cvar: UnsafeCell<libc::pthread_cond_t>,
+    // The `pthread` primitives require a stable address, so make this struct `!Unpin`.
+    _pinned: PhantomPinned,
+}
+
+impl Parker {
+    /// Construct the UNIX parker in-place.
+    ///
+    /// # Safety
+    /// The constructed parker must never be moved.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        // Use the default mutex implementation to allow for simpler initialization.
+        // This could lead to undefined behaviour when deadlocking. This is avoided
+        // by not deadlocking. Note in particular the unlocking operation before any
+        // panic, as code after the panic could try to park again.
+        addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY));
+        addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER));
+
+        cfg_if::cfg_if! {
+            if #[cfg(any(
+                target_os = "macos",
+                target_os = "ios",
+                target_os = "watchos",
+                target_os = "l4re",
+                target_os = "android",
+                target_os = "redox"
+            ))] {
+                addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER));
+            } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
+                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null());
+                assert_eq!(r, 0);
+            } else {
+                use crate::mem::MaybeUninit;
+                let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
+                let r = libc::pthread_condattr_init(attr.as_mut_ptr());
+                assert_eq!(r, 0);
+                let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
+                assert_eq!(r, 0);
+                let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr());
+                assert_eq!(r, 0);
+                let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
+                assert_eq!(r, 0);
+            }
+        }
+    }
+
+    // This implementation doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // If we were previously notified then we consume this notification and
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        // Otherwise we need to coordinate going to sleep
+        lock(self.lock.get());
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read here, even though we know it will be `NOTIFIED`.
+                // This is because `unpark` may have been called again since we read
+                // `NOTIFIED` in the `compare_exchange` above. We must perform an
+                // acquire operation that synchronizes with that `unpark` to observe
+                // any writes it made before the call to unpark. To do that we must
+                // read from the write it made to `state`.
+                let old = self.state.swap(EMPTY, SeqCst);
+
+                unlock(self.lock.get());
+
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => {
+                unlock(self.lock.get());
+
+                panic!("inconsistent park state")
+            }
+        }
+
+        loop {
+            wait(self.cvar.get(), self.lock.get());
+
+            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+                Ok(_) => break, // got a notification
+                Err(_) => {}    // spurious wakeup, go back to sleep
+            }
+        }
+
+        unlock(self.lock.get());
+    }
+
+    // This implementation doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker. Use
+    // `Pin` to guarantee a stable address for the mutex and condition variable.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        // Like `park` above we have a fast path for an already-notified thread, and
+        // afterwards we start coordinating for a sleep.
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        lock(self.lock.get());
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read again here, see `park`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                unlock(self.lock.get());
+
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => {
+                unlock(self.lock.get());
+                panic!("inconsistent park_timeout state")
+            }
+        }
+
+        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+        // from a notification we just want to unconditionally set the state back to
+        // empty, either consuming a notification or un-flagging ourselves as
+        // parked.
+        wait_timeout(self.cvar.get(), self.lock.get(), dur);
+
+        match self.state.swap(EMPTY, SeqCst) {
+            NOTIFIED => unlock(self.lock.get()), // got a notification, hurray!
+            PARKED => unlock(self.lock.get()),   // no notification, alas
+            n => {
+                unlock(self.lock.get());
+                panic!("inconsistent park_timeout state: {n}")
+            }
+        }
+    }
+
+    pub fn unpark(self: Pin<&Self>) {
+        // To ensure the unparked thread will observe any writes we made
+        // before this call, we must perform a release operation that `park`
+        // can synchronize with. To do that we must write `NOTIFIED` even if
+        // `state` is already `NOTIFIED`. That is why this must be a swap
+        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+        // on failure.
+        match self.state.swap(NOTIFIED, SeqCst) {
+            EMPTY => return,    // no one was waiting
+            NOTIFIED => return, // already unparked
+            PARKED => {}        // gotta go wake someone up
+            _ => panic!("inconsistent state in unpark"),
+        }
+
+        // There is a period between when the parked thread sets `state` to
+        // `PARKED` (or last checked `state` in the case of a spurious wake
+        // up) and when it actually waits on `cvar`. If we were to notify
+        // during this period it would be ignored and then when the parked
+        // thread went to sleep it would never wake up. Fortunately, it has
+        // `lock` locked at this stage so we can acquire `lock` to wait until
+        // it is ready to receive the notification.
+        //
+        // Releasing `lock` before the call to `notify_one` means that when the
+        // parked thread wakes it doesn't get woken only to have to wait for us
+        // to release `lock`.
+        unsafe {
+            lock(self.lock.get());
+            unlock(self.lock.get());
+            notify_one(self.cvar.get());
+        }
+    }
+}
+
+impl Drop for Parker {
+    fn drop(&mut self) {
+        unsafe {
+            libc::pthread_cond_destroy(self.cvar.get_mut());
+            libc::pthread_mutex_destroy(self.lock.get_mut());
+        }
+    }
+}
+
+unsafe impl Sync for Parker {}
+unsafe impl Send for Parker {}
index f5a4ce929b2a9219311c6c6d1298fad26c695b0c..62ffee70becc3d2d56ba87446d2f3b28ea290643 100644 (file)
@@ -1,9 +1,8 @@
 //! Support for "weak linkage" to symbols on Unix
 //!
-//! Some I/O operations we do in libstd require newer versions of OSes but we
-//! need to maintain binary compatibility with older releases for now. In order
-//! to use the new functionality when available we use this module for
-//! detection.
+//! Some I/O operations we do in std require newer versions of OSes but we need
+//! to maintain binary compatibility with older releases for now. In order to
+//! use the new functionality when available we use this module for detection.
 //!
 //! One option to use here is weak linkage, but that is unfortunately only
 //! really workable with ELF. Otherwise, use dlsym to get the symbol value at
@@ -29,7 +28,7 @@
 use crate::sync::atomic::{self, AtomicPtr, Ordering};
 
 // We can use true weak linkage on ELF targets.
-#[cfg(all(not(any(target_os = "macos", target_os = "ios")), not(bootstrap)))]
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
 pub(crate) macro weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
         let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
     )
 }
 
-#[cfg(all(not(any(target_os = "macos", target_os = "ios")), bootstrap))]
-pub(crate) macro weak {
-    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
-        let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
-            extern "C" {
-                #[linkage = "extern_weak"]
-                static $name: *const libc::c_void;
-            }
-            #[allow(unused_unsafe)]
-            ExternWeak::new(unsafe { $name })
-        };
-    )
-}
-
 // On non-ELF targets, use the dlsym approximation of weak linkage.
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 pub(crate) use self::dlsym as weak;
 
-#[cfg(not(bootstrap))]
 pub(crate) struct ExternWeak<F: Copy> {
     weak_ptr: Option<F>,
 }
 
-#[cfg(not(bootstrap))]
 impl<F: Copy> ExternWeak<F> {
     #[inline]
     pub(crate) fn new(weak_ptr: Option<F>) -> Self {
@@ -79,34 +62,6 @@ pub(crate) fn get(&self) -> Option<F> {
     }
 }
 
-#[cfg(bootstrap)]
-pub(crate) struct ExternWeak<F> {
-    weak_ptr: *const libc::c_void,
-    _marker: PhantomData<F>,
-}
-
-#[cfg(bootstrap)]
-impl<F> ExternWeak<F> {
-    #[inline]
-    pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
-        ExternWeak { weak_ptr, _marker: PhantomData }
-    }
-}
-
-#[cfg(bootstrap)]
-impl<F> ExternWeak<F> {
-    #[inline]
-    pub(crate) fn get(&self) -> Option<F> {
-        unsafe {
-            if self.weak_ptr.is_null() {
-                None
-            } else {
-                Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
-            }
-        }
-    }
-}
-
 pub(crate) macro dlsym {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
          dlsym!(fn $name($($t),*) -> $ret, stringify!($name));
index e67411e16860e679cbb83cb2c6a7080f9542a0e5..77359abe429950869a9c82bbb5477e1a2f3cd6af 100644 (file)
@@ -33,7 +33,7 @@
 pub mod thread;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod time;
 cfg_if::cfg_if! {
     if #[cfg(not(target_vendor = "uwp"))] {
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs
deleted file mode 100644 (file)
index 2f7ae86..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-// Thread parker implementation for Windows.
-//
-// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+).
-// This modern API is exactly the same as the futex syscalls the Linux thread
-// parker uses. When These APIs are available, the implementation of this
-// thread parker matches the Linux thread parker exactly.
-//
-// However, when the modern API is not available, this implementation falls
-// back to NT Keyed Events, which are similar, but have some important
-// differences. These are available since Windows XP.
-//
-// WaitOnAddress first checks the state of the thread parker to make sure it no
-// WakeByAddressSingle calls can be missed between updating the parker state
-// and calling the function.
-//
-// NtWaitForKeyedEvent does not have this option, and unconditionally blocks
-// without checking the parker state first. Instead, NtReleaseKeyedEvent
-// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for
-// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed,
-// but we need to be careful not to block unpark() if park_timeout() was woken
-// up by a timeout instead of unpark().
-//
-// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
-// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
-// a successfully awoken park() was awoken by unpark() and not a
-// NtReleaseKeyedEvent call from some other code, as these events are not only
-// matched by the key (address of the parker (state)), but also by this HANDLE.
-// We lazily allocate this handle the first time it is needed.
-//
-// The fast path (calling park() after unpark() was already called) and the
-// possible states are the same for both implementations. This is used here to
-// make sure the fast path does not even check which API to use, but can return
-// right away, independent of the used API. Only the slow paths (which will
-// actually block/wake a thread) check which API is available and have
-// different implementations.
-//
-// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
-// - This API is relatively simple with obvious behaviour, and there are
-//   several (unofficial) articles documenting the details. [1]
-// - `parking_lot` has been using this API for years (on Windows versions
-//   before Windows 8). [2] Many big projects extensively use parking_lot,
-//   such as servo and the Rust compiler itself.
-// - It is the underlying API used by Windows SRW locks and Windows critical
-//   sections. [3] [4]
-// - The source code of the implementations of Wine, ReactOs, and Windows XP
-//   are available and match the expected behaviour.
-// - The main risk with an undocumented API is that it might change in the
-//   future. But since we only use it for older versions of Windows, that's not
-//   a problem.
-// - Even if these functions do not block or wake as we expect (which is
-//   unlikely, see all previous points), this implementation would still be
-//   memory safe. The NT Keyed Events API is only used to sleep/block in the
-//   right place.
-//
-// [1]: http://www.locklessinc.com/articles/keyed_events/
-// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e
-// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
-// [4]: Windows Internals, Part 1, ISBN 9780735671300
-
-use crate::pin::Pin;
-use crate::ptr;
-use crate::sync::atomic::{
-    AtomicI8, AtomicPtr,
-    Ordering::{Acquire, Relaxed, Release},
-};
-use crate::sys::{c, dur2timeout};
-use crate::time::Duration;
-
-pub struct Parker {
-    state: AtomicI8,
-}
-
-const PARKED: i8 = -1;
-const EMPTY: i8 = 0;
-const NOTIFIED: i8 = 1;
-
-// Notes about memory ordering:
-//
-// Memory ordering is only relevant for the relative ordering of operations
-// between different variables. Even Ordering::Relaxed guarantees a
-// monotonic/consistent order when looking at just a single atomic variable.
-//
-// So, since this parker is just a single atomic variable, we only need to look
-// at the ordering guarantees we need to provide to the 'outside world'.
-//
-// The only memory ordering guarantee that parking and unparking provide, is
-// that things which happened before unpark() are visible on the thread
-// returning from park() afterwards. Otherwise, it was effectively unparked
-// before unpark() was called while still consuming the 'token'.
-//
-// In other words, unpark() needs to synchronize with the part of park() that
-// consumes the token and returns.
-//
-// This is done with a release-acquire synchronization, by using
-// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
-// Ordering::Acquire when reading this state in park() after waking up.
-impl Parker {
-    /// Construct the Windows parker. The UNIX parker implementation
-    /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
-        parker.write(Self { state: AtomicI8::new(EMPTY) });
-    }
-
-    // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
-    // but other implementations do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
-        // first case.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-
-        if let Some(wait_on_address) = c::WaitOnAddress::option() {
-            loop {
-                // Wait for something to happen, assuming it's still set to PARKED.
-                wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
-                // Change NOTIFIED=>EMPTY but leave PARKED alone.
-                if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
-                    // Actually woken up by unpark().
-                    return;
-                } else {
-                    // Spurious wake up. We loop to try again.
-                }
-            }
-        } else {
-            // Wait for unpark() to produce this event.
-            c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
-            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
-            // Note that we don't just write EMPTY, but use swap() to also
-            // include an acquire-ordered read to synchronize with unpark()'s
-            // release-ordered write.
-            self.state.swap(EMPTY, Acquire);
-        }
-    }
-
-    // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
-    // but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
-        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
-        // first case.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-
-        if let Some(wait_on_address) = c::WaitOnAddress::option() {
-            // Wait for something to happen, assuming it's still set to PARKED.
-            wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
-            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
-            // Note that we don't just write EMPTY, but use swap() to also
-            // include an acquire-ordered read to synchronize with unpark()'s
-            // release-ordered write.
-            if self.state.swap(EMPTY, Acquire) == NOTIFIED {
-                // Actually woken up by unpark().
-            } else {
-                // Timeout or spurious wake up.
-                // We return either way, because we can't easily tell if it was the
-                // timeout or not.
-            }
-        } else {
-            // Need to wait for unpark() using NtWaitForKeyedEvent.
-            let handle = keyed_event_handle();
-
-            // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative
-            // values to indicate a relative time on the monotonic clock.
-            // This is documented here for the underlying KeWaitForSingleObject function:
-            // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject
-            let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
-                Ok(t) => -t,
-                Err(_) => i64::MIN,
-            };
-
-            // Wait for unpark() to produce this event.
-            let unparked =
-                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;
-
-            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
-            let prev_state = self.state.swap(EMPTY, Acquire);
-
-            if !unparked && prev_state == NOTIFIED {
-                // We were awoken by a timeout, not by unpark(), but the state
-                // was set to NOTIFIED, which means we *just* missed an
-                // unpark(), which is now blocked on us to wait for it.
-                // Wait for it to consume the event and unblock that thread.
-                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
-            }
-        }
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    pub fn unpark(self: Pin<&Self>) {
-        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
-        // wake the thread in the first case.
-        //
-        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
-        // purpose, to make sure every unpark() has a release-acquire ordering
-        // with park().
-        if self.state.swap(NOTIFIED, Release) == PARKED {
-            unsafe {
-                if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
-                    wake_by_address_single(self.ptr());
-                } else {
-                    // If we run NtReleaseKeyedEvent before the waiting thread runs
-                    // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
-                    // If the waiting thread wakes up before we run NtReleaseKeyedEvent
-                    // (e.g. due to a timeout), this blocks until we do wake up a thread.
-                    // To prevent this thread from blocking indefinitely in that case,
-                    // park_impl() will, after seeing the state set to NOTIFIED after
-                    // waking up, call NtWaitForKeyedEvent again to unblock us.
-                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
-                }
-            }
-        }
-    }
-
-    fn ptr(&self) -> c::LPVOID {
-        &self.state as *const _ as c::LPVOID
-    }
-}
-
-fn keyed_event_handle() -> c::HANDLE {
-    const INVALID: c::HANDLE = ptr::invalid_mut(!0);
-    static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
-    match HANDLE.load(Relaxed) {
-        INVALID => {
-            let mut handle = c::INVALID_HANDLE_VALUE;
-            unsafe {
-                match c::NtCreateKeyedEvent(
-                    &mut handle,
-                    c::GENERIC_READ | c::GENERIC_WRITE,
-                    ptr::null_mut(),
-                    0,
-                ) {
-                    c::STATUS_SUCCESS => {}
-                    r => panic!("Unable to create keyed event handle: error {r}"),
-                }
-            }
-            match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) {
-                Ok(_) => handle,
-                Err(h) => {
-                    // Lost the race to another thread initializing HANDLE before we did.
-                    // Closing our handle and using theirs instead.
-                    unsafe {
-                        c::CloseHandle(handle);
-                    }
-                    h
-                }
-            }
-        }
-        handle => handle,
-    }
-}
diff --git a/library/std/src/sys/windows/thread_parking.rs b/library/std/src/sys/windows/thread_parking.rs
new file mode 100644 (file)
index 0000000..5d43676
--- /dev/null
@@ -0,0 +1,253 @@
+// Thread parker implementation for Windows.
+//
+// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+).
+// This modern API is exactly the same as the futex syscalls the Linux thread
+// parker uses. When These APIs are available, the implementation of this
+// thread parker matches the Linux thread parker exactly.
+//
+// However, when the modern API is not available, this implementation falls
+// back to NT Keyed Events, which are similar, but have some important
+// differences. These are available since Windows XP.
+//
+// WaitOnAddress first checks the state of the thread parker to make sure it no
+// WakeByAddressSingle calls can be missed between updating the parker state
+// and calling the function.
+//
+// NtWaitForKeyedEvent does not have this option, and unconditionally blocks
+// without checking the parker state first. Instead, NtReleaseKeyedEvent
+// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for
+// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed,
+// but we need to be careful not to block unpark() if park_timeout() was woken
+// up by a timeout instead of unpark().
+//
+// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
+// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
+// a successfully awoken park() was awoken by unpark() and not a
+// NtReleaseKeyedEvent call from some other code, as these events are not only
+// matched by the key (address of the parker (state)), but also by this HANDLE.
+// We lazily allocate this handle the first time it is needed.
+//
+// The fast path (calling park() after unpark() was already called) and the
+// possible states are the same for both implementations. This is used here to
+// make sure the fast path does not even check which API to use, but can return
+// right away, independent of the used API. Only the slow paths (which will
+// actually block/wake a thread) check which API is available and have
+// different implementations.
+//
+// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
+// - This API is relatively simple with obvious behaviour, and there are
+//   several (unofficial) articles documenting the details. [1]
+// - `parking_lot` has been using this API for years (on Windows versions
+//   before Windows 8). [2] Many big projects extensively use parking_lot,
+//   such as servo and the Rust compiler itself.
+// - It is the underlying API used by Windows SRW locks and Windows critical
+//   sections. [3] [4]
+// - The source code of the implementations of Wine, ReactOs, and Windows XP
+//   are available and match the expected behaviour.
+// - The main risk with an undocumented API is that it might change in the
+//   future. But since we only use it for older versions of Windows, that's not
+//   a problem.
+// - Even if these functions do not block or wake as we expect (which is
+//   unlikely, see all previous points), this implementation would still be
+//   memory safe. The NT Keyed Events API is only used to sleep/block in the
+//   right place.
+//
+// [1]: http://www.locklessinc.com/articles/keyed_events/
+// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e
+// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
+// [4]: Windows Internals, Part 1, ISBN 9780735671300
+
+use crate::pin::Pin;
+use crate::ptr;
+use crate::sync::atomic::{
+    AtomicI8, AtomicPtr,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::{c, dur2timeout};
+use crate::time::Duration;
+
+pub struct Parker {
+    state: AtomicI8,
+}
+
+const PARKED: i8 = -1;
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+
+// Notes about memory ordering:
+//
+// Memory ordering is only relevant for the relative ordering of operations
+// between different variables. Even Ordering::Relaxed guarantees a
+// monotonic/consistent order when looking at just a single atomic variable.
+//
+// So, since this parker is just a single atomic variable, we only need to look
+// at the ordering guarantees we need to provide to the 'outside world'.
+//
+// The only memory ordering guarantee that parking and unparking provide, is
+// that things which happened before unpark() are visible on the thread
+// returning from park() afterwards. Otherwise, it was effectively unparked
+// before unpark() was called while still consuming the 'token'.
+//
+// In other words, unpark() needs to synchronize with the part of park() that
+// consumes the token and returns.
+//
+// This is done with a release-acquire synchronization, by using
+// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
+// Ordering::Acquire when reading this state in park() after waking up.
+impl Parker {
+    /// Construct the Windows parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        parker.write(Self { state: AtomicI8::new(EMPTY) });
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
+    // but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+
+        if let Some(wait_on_address) = c::WaitOnAddress::option() {
+            loop {
+                // Wait for something to happen, assuming it's still set to PARKED.
+                wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
+                // Change NOTIFIED=>EMPTY but leave PARKED alone.
+                if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
+                    // Actually woken up by unpark().
+                    return;
+                } else {
+                    // Spurious wake up. We loop to try again.
+                }
+            }
+        } else {
+            // Wait for unpark() to produce this event.
+            c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
+            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
+            // Note that we don't just write EMPTY, but use swap() to also
+            // include an acquire-ordered read to synchronize with unpark()'s
+            // release-ordered write.
+            self.state.swap(EMPTY, Acquire);
+        }
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`. This implementation doesn't require `Pin`,
+    // but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+
+        if let Some(wait_on_address) = c::WaitOnAddress::option() {
+            // Wait for something to happen, assuming it's still set to PARKED.
+            wait_on_address(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
+            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
+            // Note that we don't just write EMPTY, but use swap() to also
+            // include an acquire-ordered read to synchronize with unpark()'s
+            // release-ordered write.
+            if self.state.swap(EMPTY, Acquire) == NOTIFIED {
+                // Actually woken up by unpark().
+            } else {
+                // Timeout or spurious wake up.
+                // We return either way, because we can't easily tell if it was the
+                // timeout or not.
+            }
+        } else {
+            // Need to wait for unpark() using NtWaitForKeyedEvent.
+            let handle = keyed_event_handle();
+
+            // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative
+            // values to indicate a relative time on the monotonic clock.
+            // This is documented here for the underlying KeWaitForSingleObject function:
+            // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject
+            let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
+                Ok(t) => -t,
+                Err(_) => i64::MIN,
+            };
+
+            // Wait for unpark() to produce this event.
+            let unparked =
+                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;
+
+            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
+            let prev_state = self.state.swap(EMPTY, Acquire);
+
+            if !unparked && prev_state == NOTIFIED {
+                // We were awoken by a timeout, not by unpark(), but the state
+                // was set to NOTIFIED, which means we *just* missed an
+                // unpark(), which is now blocked on us to wait for it.
+                // Wait for it to consume the event and unblock that thread.
+                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
+            }
+        }
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
+        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
+        // wake the thread in the first case.
+        //
+        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
+        // purpose, to make sure every unpark() has a release-acquire ordering
+        // with park().
+        if self.state.swap(NOTIFIED, Release) == PARKED {
+            unsafe {
+                if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
+                    wake_by_address_single(self.ptr());
+                } else {
+                    // If we run NtReleaseKeyedEvent before the waiting thread runs
+                    // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
+                    // If the waiting thread wakes up before we run NtReleaseKeyedEvent
+                    // (e.g. due to a timeout), this blocks until we do wake up a thread.
+                    // To prevent this thread from blocking indefinitely in that case,
+                    // park_impl() will, after seeing the state set to NOTIFIED after
+                    // waking up, call NtWaitForKeyedEvent again to unblock us.
+                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
+                }
+            }
+        }
+    }
+
+    fn ptr(&self) -> c::LPVOID {
+        &self.state as *const _ as c::LPVOID
+    }
+}
+
+fn keyed_event_handle() -> c::HANDLE {
+    const INVALID: c::HANDLE = ptr::invalid_mut(!0);
+    static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
+    match HANDLE.load(Relaxed) {
+        INVALID => {
+            let mut handle = c::INVALID_HANDLE_VALUE;
+            unsafe {
+                match c::NtCreateKeyedEvent(
+                    &mut handle,
+                    c::GENERIC_READ | c::GENERIC_WRITE,
+                    ptr::null_mut(),
+                    0,
+                ) {
+                    c::STATUS_SUCCESS => {}
+                    r => panic!("Unable to create keyed event handle: error {r}"),
+                }
+            }
+            match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) {
+                Ok(_) => handle,
+                Err(h) => {
+                    // Lost the race to another thread initializing HANDLE before we did.
+                    // Closing our handle and using theirs instead.
+                    unsafe {
+                        c::CloseHandle(handle);
+                    }
+                    h
+                }
+            }
+        }
+        handle => handle,
+    }
+}
index 8807077cb49271d4fba61ca74420c002cbb1cf10..f1d804ef40c0e60786d568a4249bb80e42f63b91 100644 (file)
@@ -20,7 +20,7 @@ pub fn lock() -> impl Drop {
 /// Prints the current backtrace.
 pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
     // There are issues currently linking libbacktrace into tests, and in
-    // general during libstd's own unit tests we're not testing this path. In
+    // general during std's own unit tests we're not testing this path. In
     // test mode immediately return here to optimize away any references to the
     // libbacktrace symbols
     if cfg!(test) {
@@ -111,7 +111,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
 }
 
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
-/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// this is only inline(never) when backtraces in std are enabled, otherwise
 /// it's fine to optimize away.
 #[cfg_attr(feature = "backtrace", inline(never))]
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
@@ -127,7 +127,7 @@ pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
 }
 
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
-/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// this is only inline(never) when backtraces in std are enabled, otherwise
 /// it's fine to optimize away.
 #[cfg_attr(feature = "backtrace", inline(never))]
 pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
index d1e9fed41fc930093b85b900ab5fb9e2735fcc3d..4a42ff3c618ce4c744cb2d9f479ea86926faffa8 100644 (file)
@@ -39,9 +39,10 @@ fn drop(&mut self) {
         }
     }
 
+    #[track_caller] // for `test_rng`
     pub fn tmpdir() -> TempDir {
         let p = env::temp_dir();
-        let mut r = rand::thread_rng();
+        let mut r = crate::test_helpers::test_rng();
         let ret = p.join(&format!("rust-{}", r.next_u32()));
         fs::create_dir(&ret).unwrap();
         TempDir(ret)
index b1987aa0f6286b2333e36a45aadf576e1f7a395f..6b24b0e9aa8be85129f6a62bfb074db63d39e7ec 100644 (file)
 pub mod memchr;
 pub mod once;
 pub mod process;
-pub mod remutex;
 pub mod thread;
 pub mod thread_info;
 pub mod thread_local_dtor;
-pub mod thread_parker;
+pub mod thread_parking;
 pub mod wstr;
 pub mod wtf8;
 
index ae11412067b549a719ec243442bd2beb7606c270..18883048daef195b2f99a82b0dbdea3e36698e5b 100644 (file)
@@ -4,12 +4,13 @@
 use crate::collections::BTreeMap;
 use crate::env;
 use crate::ffi::{OsStr, OsString};
+use crate::fmt;
 use crate::io;
 use crate::sys::pipe::read2;
 use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
 
 // Stores a set of changes to an environment
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct CommandEnv {
     clear: bool,
     saw_path: bool,
@@ -22,6 +23,14 @@ fn default() -> Self {
     }
 }
 
+impl fmt::Debug for CommandEnv {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut debug_command_env = f.debug_struct("CommandEnv");
+        debug_command_env.field("clear", &self.clear).field("vars", &self.vars);
+        debug_command_env.finish()
+    }
+}
+
 impl CommandEnv {
     // Capture the current environment with these changes applied
     pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs
deleted file mode 100644 (file)
index 4c054da..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests;
-
-use crate::cell::UnsafeCell;
-use crate::ops::Deref;
-use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-use crate::sys::locks as sys;
-
-/// A re-entrant mutual exclusion
-///
-/// This mutex will block *other* threads waiting for the lock to become
-/// available. The thread which has already locked the mutex can lock it
-/// multiple times without blocking, preventing a common source of deadlocks.
-///
-/// This is used by stdout().lock() and friends.
-///
-/// ## Implementation details
-///
-/// The 'owner' field tracks which thread has locked the mutex.
-///
-/// We use current_thread_unique_ptr() as the thread identifier,
-/// which is just the address of a thread local variable.
-///
-/// If `owner` is set to the identifier of the current thread,
-/// we assume the mutex is already locked and instead of locking it again,
-/// we increment `lock_count`.
-///
-/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
-/// it reaches zero.
-///
-/// `lock_count` is protected by the mutex and only accessed by the thread that has
-/// locked the mutex, so needs no synchronization.
-///
-/// `owner` can be checked by other threads that want to see if they already
-/// hold the lock, so needs to be atomic. If it compares equal, we're on the
-/// same thread that holds the mutex and memory access can use relaxed ordering
-/// since we're not dealing with multiple threads. If it compares unequal,
-/// synchronization is left to the mutex, making relaxed memory ordering for
-/// the `owner` field fine in all cases.
-pub struct ReentrantMutex<T> {
-    mutex: sys::Mutex,
-    owner: AtomicUsize,
-    lock_count: UnsafeCell<u32>,
-    data: T,
-}
-
-unsafe impl<T: Send> Send for ReentrantMutex<T> {}
-unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
-
-impl<T> UnwindSafe for ReentrantMutex<T> {}
-impl<T> RefUnwindSafe for ReentrantMutex<T> {}
-
-/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
-/// dropped (falls out of scope), the lock will be unlocked.
-///
-/// The data protected by the mutex can be accessed through this guard via its
-/// Deref implementation.
-///
-/// # Mutability
-///
-/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
-/// because implementation of the trait would violate Rust’s reference aliasing
-/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
-/// guarded data.
-#[must_use = "if unused the ReentrantMutex will immediately unlock"]
-pub struct ReentrantMutexGuard<'a, T: 'a> {
-    lock: &'a ReentrantMutex<T>,
-}
-
-impl<T> !Send for ReentrantMutexGuard<'_, T> {}
-
-impl<T> ReentrantMutex<T> {
-    /// Creates a new reentrant mutex in an unlocked state.
-    pub const fn new(t: T) -> ReentrantMutex<T> {
-        ReentrantMutex {
-            mutex: sys::Mutex::new(),
-            owner: AtomicUsize::new(0),
-            lock_count: UnsafeCell::new(0),
-            data: t,
-        }
-    }
-
-    /// Acquires a mutex, blocking the current thread until it is able to do so.
-    ///
-    /// This function will block the caller until it is available to acquire the mutex.
-    /// Upon returning, the thread is the only thread with the mutex held. When the thread
-    /// calling this method already holds the lock, the call shall succeed without
-    /// blocking.
-    ///
-    /// # Errors
-    ///
-    /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return failure if the mutex would otherwise be
-    /// acquired.
-    pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
-        let this_thread = current_thread_unique_ptr();
-        // Safety: We only touch lock_count when we own the lock.
-        unsafe {
-            if self.owner.load(Relaxed) == this_thread {
-                self.increment_lock_count();
-            } else {
-                self.mutex.lock();
-                self.owner.store(this_thread, Relaxed);
-                debug_assert_eq!(*self.lock_count.get(), 0);
-                *self.lock_count.get() = 1;
-            }
-        }
-        ReentrantMutexGuard { lock: self }
-    }
-
-    /// Attempts to acquire this lock.
-    ///
-    /// If the lock could not be acquired at this time, then `Err` is returned.
-    /// Otherwise, an RAII guard is returned.
-    ///
-    /// This function does not block.
-    ///
-    /// # Errors
-    ///
-    /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return failure if the mutex would otherwise be
-    /// acquired.
-    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
-        let this_thread = current_thread_unique_ptr();
-        // Safety: We only touch lock_count when we own the lock.
-        unsafe {
-            if self.owner.load(Relaxed) == this_thread {
-                self.increment_lock_count();
-                Some(ReentrantMutexGuard { lock: self })
-            } else if self.mutex.try_lock() {
-                self.owner.store(this_thread, Relaxed);
-                debug_assert_eq!(*self.lock_count.get(), 0);
-                *self.lock_count.get() = 1;
-                Some(ReentrantMutexGuard { lock: self })
-            } else {
-                None
-            }
-        }
-    }
-
-    unsafe fn increment_lock_count(&self) {
-        *self.lock_count.get() = (*self.lock_count.get())
-            .checked_add(1)
-            .expect("lock count overflow in reentrant mutex");
-    }
-}
-
-impl<T> Deref for ReentrantMutexGuard<'_, T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        &self.lock.data
-    }
-}
-
-impl<T> Drop for ReentrantMutexGuard<'_, T> {
-    #[inline]
-    fn drop(&mut self) {
-        // Safety: We own the lock.
-        unsafe {
-            *self.lock.lock_count.get() -= 1;
-            if *self.lock.lock_count.get() == 0 {
-                self.lock.owner.store(0, Relaxed);
-                self.lock.mutex.unlock();
-            }
-        }
-    }
-}
-
-/// Get an address that is unique per running thread.
-///
-/// This can be used as a non-null usize-sized ID.
-pub fn current_thread_unique_ptr() -> usize {
-    // Use a non-drop type to make sure it's still available during thread destruction.
-    thread_local! { static X: u8 = const { 0 } }
-    X.with(|x| <*const _>::addr(x))
-}
diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs
deleted file mode 100644 (file)
index 8e97ce1..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-use crate::cell::RefCell;
-use crate::sync::Arc;
-use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use crate::thread;
-
-#[test]
-fn smoke() {
-    let m = ReentrantMutex::new(());
-    {
-        let a = m.lock();
-        {
-            let b = m.lock();
-            {
-                let c = m.lock();
-                assert_eq!(*c, ());
-            }
-            assert_eq!(*b, ());
-        }
-        assert_eq!(*a, ());
-    }
-}
-
-#[test]
-fn is_mutex() {
-    let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
-    let m2 = m.clone();
-    let lock = m.lock();
-    let child = thread::spawn(move || {
-        let lock = m2.lock();
-        assert_eq!(*lock.borrow(), 4950);
-    });
-    for i in 0..100 {
-        let lock = m.lock();
-        *lock.borrow_mut() += i;
-    }
-    drop(lock);
-    child.join().unwrap();
-}
-
-#[test]
-fn trylock_works() {
-    let m = Arc::new(ReentrantMutex::new(()));
-    let m2 = m.clone();
-    let _lock = m.try_lock();
-    let _lock2 = m.try_lock();
-    thread::spawn(move || {
-        let lock = m2.try_lock();
-        assert!(lock.is_none());
-    })
-    .join()
-    .unwrap();
-    let _lock3 = m.try_lock();
-}
-
-pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
-impl Drop for Answer<'_> {
-    fn drop(&mut self) {
-        *self.0.borrow_mut() = 42;
-    }
-}
index 747579f178127c2897268a6df906f49dc7cd2601..2672a2a75b017bc4cec15931f3f68cfad622f7ea 100644 (file)
@@ -117,10 +117,14 @@ pub struct Key {
 /// This value specifies no destructor by default.
 pub const INIT: StaticKey = StaticKey::new(None);
 
+// Define a sentinel value that is unlikely to be returned
+// as a TLS key (but it may be returned).
+const KEY_SENTVAL: usize = 0;
+
 impl StaticKey {
     #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
     pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
-        StaticKey { key: atomic::AtomicUsize::new(0), dtor }
+        StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
     }
 
     /// Gets the value associated with this TLS key
@@ -144,31 +148,36 @@ pub unsafe fn set(&self, val: *mut u8) {
     #[inline]
     unsafe fn key(&self) -> imp::Key {
         match self.key.load(Ordering::Relaxed) {
-            0 => self.lazy_init() as imp::Key,
+            KEY_SENTVAL => self.lazy_init() as imp::Key,
             n => n as imp::Key,
         }
     }
 
     unsafe fn lazy_init(&self) -> usize {
-        // POSIX allows the key created here to be 0, but the compare_exchange
-        // below relies on using 0 as a sentinel value to check who won the
+        // POSIX allows the key created here to be KEY_SENTVAL, but the compare_exchange
+        // below relies on using KEY_SENTVAL as a sentinel value to check who won the
         // race to set the shared TLS key. As far as I know, there is no
         // guaranteed value that cannot be returned as a posix_key_create key,
         // so there is no value we can initialize the inner key with to
         // prove that it has not yet been set. As such, we'll continue using a
-        // value of 0, but with some gyrations to make sure we have a non-0
+        // value of KEY_SENTVAL, but with some gyrations to make sure we have a non-KEY_SENTVAL
         // value returned from the creation routine.
         // FIXME: this is clearly a hack, and should be cleaned up.
         let key1 = imp::create(self.dtor);
-        let key = if key1 != 0 {
+        let key = if key1 as usize != KEY_SENTVAL {
             key1
         } else {
             let key2 = imp::create(self.dtor);
             imp::destroy(key1);
             key2
         };
-        rtassert!(key != 0);
-        match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
+        rtassert!(key as usize != KEY_SENTVAL);
+        match self.key.compare_exchange(
+            KEY_SENTVAL,
+            key as usize,
+            Ordering::SeqCst,
+            Ordering::SeqCst,
+        ) {
             // The CAS succeeded, so we've created the actual key
             Ok(_) => key as usize,
             // If someone beat us to the punch, use their key instead
diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs
deleted file mode 100644 (file)
index d9e2f39..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicU32;
-use crate::sync::atomic::Ordering::{Acquire, Release};
-use crate::sys::futex::{futex_wait, futex_wake};
-use crate::time::Duration;
-
-const PARKED: u32 = u32::MAX;
-const EMPTY: u32 = 0;
-const NOTIFIED: u32 = 1;
-
-pub struct Parker {
-    state: AtomicU32,
-}
-
-// Notes about memory ordering:
-//
-// Memory ordering is only relevant for the relative ordering of operations
-// between different variables. Even Ordering::Relaxed guarantees a
-// monotonic/consistent order when looking at just a single atomic variable.
-//
-// So, since this parker is just a single atomic variable, we only need to look
-// at the ordering guarantees we need to provide to the 'outside world'.
-//
-// The only memory ordering guarantee that parking and unparking provide, is
-// that things which happened before unpark() are visible on the thread
-// returning from park() afterwards. Otherwise, it was effectively unparked
-// before unpark() was called while still consuming the 'token'.
-//
-// In other words, unpark() needs to synchronize with the part of park() that
-// consumes the token and returns.
-//
-// This is done with a release-acquire synchronization, by using
-// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
-// Ordering::Acquire when checking for this state in park().
-impl Parker {
-    /// Construct the futex parker. The UNIX parker implementation
-    /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
-        parker.write(Self { state: AtomicU32::new(EMPTY) });
-    }
-
-    // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
-        // first case.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-        loop {
-            // Wait for something to happen, assuming it's still set to PARKED.
-            futex_wait(&self.state, PARKED, None);
-            // Change NOTIFIED=>EMPTY and return in that case.
-            if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
-                return;
-            } else {
-                // Spurious wake up. We loop to try again.
-            }
-        }
-    }
-
-    // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`. This implementation doesn't
-    // require `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
-        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
-        // first case.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-        // Wait for something to happen, assuming it's still set to PARKED.
-        futex_wait(&self.state, PARKED, Some(timeout));
-        // This is not just a store, because we need to establish a
-        // release-acquire ordering with unpark().
-        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
-            // Woke up because of unpark().
-        } else {
-            // Timeout or spurious wake up.
-            // We return either way, because we can't easily tell if it was the
-            // timeout or not.
-        }
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    #[inline]
-    pub fn unpark(self: Pin<&Self>) {
-        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
-        // wake the thread in the first case.
-        //
-        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
-        // purpose, to make sure every unpark() has a release-acquire ordering
-        // with park().
-        if self.state.swap(NOTIFIED, Release) == PARKED {
-            futex_wake(&self.state);
-        }
-    }
-}
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs
deleted file mode 100644 (file)
index f3d8b34..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-//! Parker implementation based on a Mutex and Condvar.
-
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sync::{Condvar, Mutex};
-use crate::time::Duration;
-
-const EMPTY: usize = 0;
-const PARKED: usize = 1;
-const NOTIFIED: usize = 2;
-
-pub struct Parker {
-    state: AtomicUsize,
-    lock: Mutex<()>,
-    cvar: Condvar,
-}
-
-impl Parker {
-    /// Construct the generic parker. The UNIX parker implementation
-    /// requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
-        parker.write(Parker {
-            state: AtomicUsize::new(EMPTY),
-            lock: Mutex::new(()),
-            cvar: Condvar::new(),
-        });
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // If we were previously notified then we consume this notification and
-        // return quickly.
-        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-            return;
-        }
-
-        // Otherwise we need to coordinate going to sleep
-        let mut m = self.lock.lock().unwrap();
-        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-            Ok(_) => {}
-            Err(NOTIFIED) => {
-                // We must read here, even though we know it will be `NOTIFIED`.
-                // This is because `unpark` may have been called again since we read
-                // `NOTIFIED` in the `compare_exchange` above. We must perform an
-                // acquire operation that synchronizes with that `unpark` to observe
-                // any writes it made before the call to unpark. To do that we must
-                // read from the write it made to `state`.
-                let old = self.state.swap(EMPTY, SeqCst);
-                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-                return;
-            } // should consume this notification, so prohibit spurious wakeups in next park.
-            Err(_) => panic!("inconsistent park state"),
-        }
-        loop {
-            m = self.cvar.wait(m).unwrap();
-            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
-                Ok(_) => return, // got a notification
-                Err(_) => {}     // spurious wakeup, go back to sleep
-            }
-        }
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        // Like `park` above we have a fast path for an already-notified thread, and
-        // afterwards we start coordinating for a sleep.
-        // return quickly.
-        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-            return;
-        }
-        let m = self.lock.lock().unwrap();
-        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-            Ok(_) => {}
-            Err(NOTIFIED) => {
-                // We must read again here, see `park`.
-                let old = self.state.swap(EMPTY, SeqCst);
-                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-                return;
-            } // should consume this notification, so prohibit spurious wakeups in next park.
-            Err(_) => panic!("inconsistent park_timeout state"),
-        }
-
-        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
-        // from a notification we just want to unconditionally set the state back to
-        // empty, either consuming a notification or un-flagging ourselves as
-        // parked.
-        let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap();
-        match self.state.swap(EMPTY, SeqCst) {
-            NOTIFIED => {} // got a notification, hurray!
-            PARKED => {}   // no notification, alas
-            n => panic!("inconsistent park_timeout state: {n}"),
-        }
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    pub fn unpark(self: Pin<&Self>) {
-        // To ensure the unparked thread will observe any writes we made
-        // before this call, we must perform a release operation that `park`
-        // can synchronize with. To do that we must write `NOTIFIED` even if
-        // `state` is already `NOTIFIED`. That is why this must be a swap
-        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
-        // on failure.
-        match self.state.swap(NOTIFIED, SeqCst) {
-            EMPTY => return,    // no one was waiting
-            NOTIFIED => return, // already unparked
-            PARKED => {}        // gotta go wake someone up
-            _ => panic!("inconsistent state in unpark"),
-        }
-
-        // There is a period between when the parked thread sets `state` to
-        // `PARKED` (or last checked `state` in the case of a spurious wake
-        // up) and when it actually waits on `cvar`. If we were to notify
-        // during this period it would be ignored and then when the parked
-        // thread went to sleep it would never wake up. Fortunately, it has
-        // `lock` locked at this stage so we can acquire `lock` to wait until
-        // it is ready to receive the notification.
-        //
-        // Releasing `lock` before the call to `notify_one` means that when the
-        // parked thread wakes it doesn't get woken only to have to wait for us
-        // to release `lock`.
-        drop(self.lock.lock().unwrap());
-        self.cvar.notify_one()
-    }
-}
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
deleted file mode 100644 (file)
index 08a2bdd..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_os = "linux",
-        target_os = "android",
-        all(target_arch = "wasm32", target_feature = "atomics"),
-        target_os = "freebsd",
-        target_os = "openbsd",
-        target_os = "dragonfly",
-        target_os = "fuchsia",
-        target_os = "hermit",
-    ))] {
-        mod futex;
-        pub use futex::Parker;
-    } else if #[cfg(target_os = "solid_asp3")] {
-        mod wait_flag;
-        pub use wait_flag::Parker;
-    } else if #[cfg(any(windows, target_family = "unix"))] {
-        pub use crate::sys::thread_parker::Parker;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
-        pub use crate::sys::thread_parker::Parker;
-    } else {
-        mod generic;
-        pub use generic::Parker;
-    }
-}
diff --git a/library/std/src/sys_common/thread_parker/wait_flag.rs b/library/std/src/sys_common/thread_parker/wait_flag.rs
deleted file mode 100644 (file)
index 6561c18..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-//! A wait-flag-based thread parker.
-//!
-//! Some operating systems provide low-level parking primitives like wait counts,
-//! event flags or semaphores which are not susceptible to race conditions (meaning
-//! the wakeup can occur before the wait operation). To implement the `std` thread
-//! parker on top of these primitives, we only have to ensure that parking is fast
-//! when the thread token is available, the atomic ordering guarantees are maintained
-//! and spurious wakeups are minimized.
-//!
-//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
-//! `PARKED` and `NOTIFIED`:
-//! * `EMPTY` means the token has not been made available, but the thread is not
-//!    currently waiting on it.
-//! * `PARKED` means the token is not available and the thread is parked.
-//! * `NOTIFIED` means the token is available.
-//!
-//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
-//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
-//! execution can continue without calling into the OS. If the state was `EMPTY`,
-//! the token is not available and the thread waits on the primitive (here called
-//! "wait flag").
-//!
-//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
-//! is or will be sleeping on the wait flag, so we raise it.
-
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicI8;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sys::wait_flag::WaitFlag;
-use crate::time::Duration;
-
-const EMPTY: i8 = 0;
-const PARKED: i8 = -1;
-const NOTIFIED: i8 = 1;
-
-pub struct Parker {
-    state: AtomicI8,
-    wait_flag: WaitFlag,
-}
-
-impl Parker {
-    /// Construct a parker for the current thread. The UNIX parker
-    /// implementation requires this to happen in-place.
-    pub unsafe fn new(parker: *mut Parker) {
-        parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park(self: Pin<&Self>) {
-        match self.state.fetch_sub(1, Acquire) {
-            // NOTIFIED => EMPTY
-            NOTIFIED => return,
-            // EMPTY => PARKED
-            EMPTY => (),
-            _ => panic!("inconsistent park state"),
-        }
-
-        // Avoid waking up from spurious wakeups (these are quite likely, see below).
-        loop {
-            self.wait_flag.wait();
-
-            match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
-                Ok(_) => return,
-                Err(PARKED) => (),
-                Err(_) => panic!("inconsistent park state"),
-            }
-        }
-    }
-
-    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        match self.state.fetch_sub(1, Acquire) {
-            NOTIFIED => return,
-            EMPTY => (),
-            _ => panic!("inconsistent park state"),
-        }
-
-        self.wait_flag.wait_timeout(dur);
-
-        // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
-        // a race condition when `unpark` is performed between receiving the timeout and
-        // resetting the state, resulting in the eventflag being set unnecessarily. `park`
-        // is protected against this by looping until the token is actually given, but
-        // here we cannot easily tell.
-
-        // Use `swap` to provide acquire ordering.
-        match self.state.swap(EMPTY, Acquire) {
-            NOTIFIED => (),
-            PARKED => (),
-            _ => panic!("inconsistent park state"),
-        }
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-
-        if state == PARKED {
-            self.wait_flag.raise();
-        }
-    }
-}
diff --git a/library/std/src/sys_common/thread_parking/futex.rs b/library/std/src/sys_common/thread_parking/futex.rs
new file mode 100644 (file)
index 0000000..588e7b2
--- /dev/null
@@ -0,0 +1,97 @@
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicU32;
+use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sys::futex::{futex_wait, futex_wake};
+use crate::time::Duration;
+
+const PARKED: u32 = u32::MAX;
+const EMPTY: u32 = 0;
+const NOTIFIED: u32 = 1;
+
+pub struct Parker {
+    state: AtomicU32,
+}
+
+// Notes about memory ordering:
+//
+// Memory ordering is only relevant for the relative ordering of operations
+// between different variables. Even Ordering::Relaxed guarantees a
+// monotonic/consistent order when looking at just a single atomic variable.
+//
+// So, since this parker is just a single atomic variable, we only need to look
+// at the ordering guarantees we need to provide to the 'outside world'.
+//
+// The only memory ordering guarantee that parking and unparking provide, is
+// that things which happened before unpark() are visible on the thread
+// returning from park() afterwards. Otherwise, it was effectively unparked
+// before unpark() was called while still consuming the 'token'.
+//
+// In other words, unpark() needs to synchronize with the part of park() that
+// consumes the token and returns.
+//
+// This is done with a release-acquire synchronization, by using
+// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
+// Ordering::Acquire when checking for this state in park().
+impl Parker {
+    /// Construct the futex parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        parker.write(Self { state: AtomicU32::new(EMPTY) });
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+        loop {
+            // Wait for something to happen, assuming it's still set to PARKED.
+            futex_wait(&self.state, PARKED, None);
+            // Change NOTIFIED=>EMPTY and return in that case.
+            if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
+                return;
+            } else {
+                // Spurious wake up. We loop to try again.
+            }
+        }
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`. This implementation doesn't
+    // require `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+        // Wait for something to happen, assuming it's still set to PARKED.
+        futex_wait(&self.state, PARKED, Some(timeout));
+        // This is not just a store, because we need to establish a
+        // release-acquire ordering with unpark().
+        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
+            // Woke up because of unpark().
+        } else {
+            // Timeout or spurious wake up.
+            // We return either way, because we can't easily tell if it was the
+            // timeout or not.
+        }
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    #[inline]
+    pub fn unpark(self: Pin<&Self>) {
+        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
+        // wake the thread in the first case.
+        //
+        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
+        // purpose, to make sure every unpark() has a release-acquire ordering
+        // with park().
+        if self.state.swap(NOTIFIED, Release) == PARKED {
+            futex_wake(&self.state);
+        }
+    }
+}
diff --git a/library/std/src/sys_common/thread_parking/generic.rs b/library/std/src/sys_common/thread_parking/generic.rs
new file mode 100644 (file)
index 0000000..3209bff
--- /dev/null
@@ -0,0 +1,125 @@
+//! Parker implementation based on a Mutex and Condvar.
+
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::{Condvar, Mutex};
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+pub struct Parker {
+    state: AtomicUsize,
+    lock: Mutex<()>,
+    cvar: Condvar,
+}
+
+impl Parker {
+    /// Construct the generic parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        parker.write(Parker {
+            state: AtomicUsize::new(EMPTY),
+            lock: Mutex::new(()),
+            cvar: Condvar::new(),
+        });
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        // If we were previously notified then we consume this notification and
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        // Otherwise we need to coordinate going to sleep
+        let mut m = self.lock.lock().unwrap();
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read here, even though we know it will be `NOTIFIED`.
+                // This is because `unpark` may have been called again since we read
+                // `NOTIFIED` in the `compare_exchange` above. We must perform an
+                // acquire operation that synchronizes with that `unpark` to observe
+                // any writes it made before the call to unpark. To do that we must
+                // read from the write it made to `state`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => panic!("inconsistent park state"),
+        }
+        loop {
+            m = self.cvar.wait(m).unwrap();
+            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+                Ok(_) => return, // got a notification
+                Err(_) => {}     // spurious wakeup, go back to sleep
+            }
+        }
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        // Like `park` above we have a fast path for an already-notified thread, and
+        // afterwards we start coordinating for a sleep.
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+        let m = self.lock.lock().unwrap();
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read again here, see `park`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => panic!("inconsistent park_timeout state"),
+        }
+
+        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+        // from a notification we just want to unconditionally set the state back to
+        // empty, either consuming a notification or un-flagging ourselves as
+        // parked.
+        let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap();
+        match self.state.swap(EMPTY, SeqCst) {
+            NOTIFIED => {} // got a notification, hurray!
+            PARKED => {}   // no notification, alas
+            n => panic!("inconsistent park_timeout state: {n}"),
+        }
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
+        // To ensure the unparked thread will observe any writes we made
+        // before this call, we must perform a release operation that `park`
+        // can synchronize with. To do that we must write `NOTIFIED` even if
+        // `state` is already `NOTIFIED`. That is why this must be a swap
+        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+        // on failure.
+        match self.state.swap(NOTIFIED, SeqCst) {
+            EMPTY => return,    // no one was waiting
+            NOTIFIED => return, // already unparked
+            PARKED => {}        // gotta go wake someone up
+            _ => panic!("inconsistent state in unpark"),
+        }
+
+        // There is a period between when the parked thread sets `state` to
+        // `PARKED` (or last checked `state` in the case of a spurious wake
+        // up) and when it actually waits on `cvar`. If we were to notify
+        // during this period it would be ignored and then when the parked
+        // thread went to sleep it would never wake up. Fortunately, it has
+        // `lock` locked at this stage so we can acquire `lock` to wait until
+        // it is ready to receive the notification.
+        //
+        // Releasing `lock` before the call to `notify_one` means that when the
+        // parked thread wakes it doesn't get woken only to have to wait for us
+        // to release `lock`.
+        drop(self.lock.lock().unwrap());
+        self.cvar.notify_one()
+    }
+}
diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs
new file mode 100644 (file)
index 0000000..e981695
--- /dev/null
@@ -0,0 +1,108 @@
+//! Thread parking using thread ids.
+//!
+//! Some platforms (notably NetBSD) have thread parking primitives whose semantics
+//! match those offered by `thread::park`, with the difference that the thread to
+//! be unparked is referenced by a platform-specific thread id. Since the thread
+//! parker is constructed before that id is known, an atomic state variable is used
+//! to manage the park state and propagate the thread id. This also avoids platform
+//! calls in the case where `unpark` is called before `park`.
+
+use crate::cell::UnsafeCell;
+use crate::pin::Pin;
+use crate::sync::atomic::{
+    fence, AtomicI8,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::thread_parking::{current, park, park_timeout, unpark, ThreadId};
+use crate::time::Duration;
+
+pub struct Parker {
+    state: AtomicI8,
+    tid: UnsafeCell<Option<ThreadId>>,
+}
+
+const PARKED: i8 = -1;
+const EMPTY: i8 = 0;
+const NOTIFIED: i8 = 1;
+
+impl Parker {
+    pub fn new() -> Parker {
+        Parker { state: AtomicI8::new(EMPTY), tid: UnsafeCell::new(None) }
+    }
+
+    /// Create a new thread parker. UNIX requires this to happen in-place.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        parker.write(Parker::new())
+    }
+
+    /// # Safety
+    /// * must always be called from the same thread
+    /// * must be called before the state is set to PARKED
+    unsafe fn init_tid(&self) {
+        // The field is only ever written to from this thread, so we don't need
+        // synchronization to read it here.
+        if self.tid.get().read().is_none() {
+            // Because this point is only reached once, before the state is set
+            // to PARKED for the first time, the non-atomic write here can not
+            // conflict with reads by other threads.
+            self.tid.get().write(Some(current()));
+            // Ensure that the write can be observed by all threads reading the
+            // state. Synchronizes with the acquire barrier in `unpark`.
+            fence(Release);
+        }
+    }
+
+    pub unsafe fn park(self: Pin<&Self>) {
+        self.init_tid();
+
+        // Changes NOTIFIED to EMPTY and EMPTY to PARKED.
+        let mut state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
+        if state == PARKED {
+            // Loop to guard against spurious wakeups.
+            while state == PARKED {
+                park(self.state.as_mut_ptr().addr());
+                state = self.state.load(Acquire);
+            }
+
+            // Since the state change has already been observed with acquire
+            // ordering, the state can be reset with a relaxed store instead
+            // of a swap.
+            self.state.store(EMPTY, Relaxed);
+        }
+    }
+
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        self.init_tid();
+
+        let state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
+        if state == PARKED {
+            park_timeout(dur, self.state.as_mut_ptr().addr());
+            // Swap to ensure that we observe all state changes with acquire
+            // ordering, even if the state has been changed after the timeout
+            // occured.
+            self.state.swap(EMPTY, Acquire);
+        }
+    }
+
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+        if state == PARKED {
+            // Synchronize with the release fence in `init_tid` to observe the
+            // write to `tid`.
+            fence(Acquire);
+            // # Safety
+            // The thread id is initialized before the state is set to `PARKED`
+            // for the first time and is not written to from that point on
+            // (negating the need for an atomic read).
+            let tid = unsafe { self.tid.get().read().unwrap_unchecked() };
+            // It is possible that the waiting thread woke up because of a timeout
+            // and terminated before this call is made. This call then returns an
+            // error or wakes up an unrelated thread. The platform API and
+            // environment does allow this, however.
+            unpark(tid, self.state.as_mut_ptr().addr());
+        }
+    }
+}
+
+unsafe impl Send for Parker {}
+unsafe impl Sync for Parker {}
diff --git a/library/std/src/sys_common/thread_parking/mod.rs b/library/std/src/sys_common/thread_parking/mod.rs
new file mode 100644 (file)
index 0000000..0ead663
--- /dev/null
@@ -0,0 +1,29 @@
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux",
+        target_os = "android",
+        all(target_arch = "wasm32", target_feature = "atomics"),
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "dragonfly",
+        target_os = "fuchsia",
+        target_os = "hermit",
+    ))] {
+        mod futex;
+        pub use futex::Parker;
+    } else if #[cfg(any(
+        target_os = "netbsd",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+    ))] {
+        mod id;
+        pub use id::Parker;
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod wait_flag;
+        pub use wait_flag::Parker;
+    } else if #[cfg(any(windows, target_family = "unix"))] {
+        pub use crate::sys::thread_parking::Parker;
+    } else {
+        mod generic;
+        pub use generic::Parker;
+    }
+}
diff --git a/library/std/src/sys_common/thread_parking/wait_flag.rs b/library/std/src/sys_common/thread_parking/wait_flag.rs
new file mode 100644 (file)
index 0000000..d0f8899
--- /dev/null
@@ -0,0 +1,102 @@
+//! A wait-flag-based thread parker.
+//!
+//! Some operating systems provide low-level parking primitives like wait counts,
+//! event flags or semaphores which are not susceptible to race conditions (meaning
+//! the wakeup can occur before the wait operation). To implement the `std` thread
+//! parker on top of these primitives, we only have to ensure that parking is fast
+//! when the thread token is available, the atomic ordering guarantees are maintained
+//! and spurious wakeups are minimized.
+//!
+//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
+//! `PARKED` and `NOTIFIED`:
+//! * `EMPTY` means the token has not been made available, but the thread is not
+//!    currently waiting on it.
+//! * `PARKED` means the token is not available and the thread is parked.
+//! * `NOTIFIED` means the token is available.
+//!
+//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
+//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
+//! execution can continue without calling into the OS. If the state was `EMPTY`,
+//! the token is not available and the thread waits on the primitive (here called
+//! "wait flag").
+//!
+//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
+//! is or will be sleeping on the wait flag, so we raise it.
+
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicI8;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sys::wait_flag::WaitFlag;
+use crate::time::Duration;
+
+const EMPTY: i8 = 0;
+const PARKED: i8 = -1;
+const NOTIFIED: i8 = 1;
+
+pub struct Parker {
+    state: AtomicI8,
+    wait_flag: WaitFlag,
+}
+
+impl Parker {
+    /// Construct a parker for the current thread. The UNIX parker
+    /// implementation requires this to happen in-place.
+    pub unsafe fn new_in_place(parker: *mut Parker) {
+        parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        match self.state.fetch_sub(1, Acquire) {
+            // NOTIFIED => EMPTY
+            NOTIFIED => return,
+            // EMPTY => PARKED
+            EMPTY => (),
+            _ => panic!("inconsistent park state"),
+        }
+
+        // Avoid waking up from spurious wakeups (these are quite likely, see below).
+        loop {
+            self.wait_flag.wait();
+
+            match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
+                Ok(_) => return,
+                Err(PARKED) => (),
+                Err(_) => panic!("inconsistent park state"),
+            }
+        }
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        match self.state.fetch_sub(1, Acquire) {
+            NOTIFIED => return,
+            EMPTY => (),
+            _ => panic!("inconsistent park state"),
+        }
+
+        self.wait_flag.wait_timeout(dur);
+
+        // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
+        // a race condition when `unpark` is performed between receiving the timeout and
+        // resetting the state, resulting in the eventflag being set unnecessarily. `park`
+        // is protected against this by looping until the token is actually given, but
+        // here we cannot easily tell.
+
+        // Use `swap` to provide acquire ordering.
+        match self.state.swap(EMPTY, Acquire) {
+            NOTIFIED => (),
+            PARKED => (),
+            _ => panic!("inconsistent park state"),
+        }
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+
+        if state == PARKED {
+            self.wait_flag.raise();
+        }
+    }
+}
index 5d267891bb0ed3b1538541624a3922134bbbb3b1..b30bb7b77efb25bdc1e7e43358eaa3c702a8779b 100644 (file)
@@ -905,9 +905,8 @@ pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> {
 pub mod fast {
     use super::lazy::LazyKeyInner;
     use crate::cell::Cell;
-    use crate::fmt;
-    use crate::mem;
     use crate::sys::thread_local_dtor::register_dtor;
+    use crate::{fmt, mem, panic};
 
     #[derive(Copy, Clone)]
     enum DtorState {
@@ -950,7 +949,7 @@ pub const fn new() -> Key<T> {
 
         // note that this is just a publicly-callable function only for the
         // const-initialized form of thread locals, basically a way to call the
-        // free `register_dtor` function defined elsewhere in libstd.
+        // free `register_dtor` function defined elsewhere in std.
         pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
             unsafe {
                 register_dtor(a, dtor);
@@ -1028,10 +1027,15 @@ unsafe fn try_register_dtor(&self) -> bool {
         // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
         // causes future calls to `get` to run `try_initialize_drop` again,
         // which will now fail, and return `None`.
-        unsafe {
+        //
+        // Wrap the call in a catch to ensure unwinding is caught in the event
+        // a panic takes place in a destructor.
+        if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
             let value = (*ptr).inner.take();
             (*ptr).dtor_state.set(DtorState::RunningOrHasRun);
             drop(value);
+        })) {
+            rtabort!("thread local panicked on drop");
         }
     }
 }
@@ -1044,10 +1048,8 @@ unsafe fn try_register_dtor(&self) -> bool {
 pub mod os {
     use super::lazy::LazyKeyInner;
     use crate::cell::Cell;
-    use crate::fmt;
-    use crate::marker;
-    use crate::ptr;
     use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
+    use crate::{fmt, marker, panic, ptr};
 
     /// Use a regular global static to store this key; the state provided will then be
     /// thread-local.
@@ -1137,12 +1139,17 @@ unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'st
         //
         // Note that to prevent an infinite loop we reset it back to null right
         // before we return from the destructor ourselves.
-        unsafe {
+        //
+        // Wrap the call in a catch to ensure unwinding is caught in the event
+        // a panic takes place in a destructor.
+        if let Err(_) = panic::catch_unwind(|| unsafe {
             let ptr = Box::from_raw(ptr as *mut Value<T>);
             let key = ptr.key;
             key.os.set(ptr::invalid_mut(1));
             drop(ptr);
             key.os.set(ptr::null_mut());
+        }) {
+            rtabort!("thread local panicked on drop");
         }
     }
 }
index 34bdb8bd4612e600d1ea3bb617bbb555172c4f35..7acda8e98f18fcf75bf3b8f97334832b949bb0f6 100644 (file)
 use crate::sys::thread as imp;
 use crate::sys_common::thread;
 use crate::sys_common::thread_info;
-use crate::sys_common::thread_parker::Parker;
+use crate::sys_common::thread_parking::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::Duration;
 
@@ -1216,7 +1216,7 @@ pub(crate) fn new(name: Option<CString>) -> Thread {
             let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
             addr_of_mut!((*ptr).name).write(name);
             addr_of_mut!((*ptr).id).write(ThreadId::new());
-            Parker::new(addr_of_mut!((*ptr).parker));
+            Parker::new_in_place(addr_of_mut!((*ptr).parker));
             Pin::new_unchecked(arc.assume_init())
         };
 
index b095c2dde628536baedfb755d55bea55cc0671f3..aae2c49d8982e8a10de8ca331b26b6df9d3381bf 100644 (file)
@@ -1,12 +1,24 @@
 use std::env::*;
 use std::ffi::{OsStr, OsString};
 
-use rand::distributions::Alphanumeric;
-use rand::{thread_rng, Rng};
+use rand::distributions::{Alphanumeric, DistString};
+
+/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+/// seed not being the same for every RNG invocation too.
+#[track_caller]
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+    use core::hash::{BuildHasher, Hash, Hasher};
+    let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+    core::panic::Location::caller().hash(&mut hasher);
+    let hc64 = hasher.finish();
+    let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+    let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+    rand::SeedableRng::from_seed(seed)
+}
 
+#[track_caller]
 fn make_rand_name() -> OsString {
-    let rng = thread_rng();
-    let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10).collect::<String>());
+    let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10));
     let n = OsString::from(n);
     assert!(var_os(&n).is_none());
     n
index 02c076f1bb5f94c0b25f93784b904dfec77bba9c..1a2c125566139d11370637b368d3d954314586ff 100644 (file)
@@ -1,9 +1,8 @@
-//! These tests just check that the macros are available in libstd.
+//! These tests just check that the macros are available in std.
 
 #![cfg_attr(
     any(
         all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
-        all(bootstrap, target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
         all(target_arch = "powerpc", target_os = "linux"),
         all(target_arch = "powerpc64", target_os = "linux"),
     ),
index a3c39f71f08b88ef38fd3e7673a78d062a78f630..24cbe035f2fa7e3e9082d38a6c44355dd47711da 100644 (file)
@@ -147,7 +147,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
     let mut ntest = 0;
     let mut nbench = 0;
 
-    for test in filter_tests(&opts, tests).into_iter() {
+    for test in filter_tests(opts, tests).into_iter() {
         use crate::TestFn::*;
 
         let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
@@ -244,7 +244,7 @@ fn on_test_event(
             let stdout = &completed_test.stdout;
 
             st.write_log_result(test, result, exec_time.as_ref())?;
-            out.write_result(test, result, exec_time.as_ref(), &*stdout, st)?;
+            out.write_result(test, result, exec_time.as_ref(), stdout, st)?;
             handle_test_result(st, completed_test);
         }
     }
@@ -262,7 +262,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
 
     let max_name_len = tests
         .iter()
-        .max_by_key(|t| len_if_padded(*t))
+        .max_by_key(|t| len_if_padded(t))
         .map(|t| t.desc.name.as_slice().len())
         .unwrap_or(0);
 
index 5526aadb67ffb84a4aafab0bd79d8ab4c12a85bf..95d2faf25060fcb0f49ef11d5b66daa895d66406 100644 (file)
@@ -40,20 +40,20 @@ fn write_event(
         extra: Option<&str>,
     ) -> io::Result<()> {
         // A doc test's name includes a filename which must be escaped for correct json.
-        self.write_message(&*format!(
+        self.write_message(&format!(
             r#"{{ "type": "{}", "name": "{}", "event": "{}""#,
             ty,
             EscapedString(name),
             evt
         ))?;
         if let Some(exec_time) = exec_time {
-            self.write_message(&*format!(r#", "exec_time": {}"#, exec_time.0.as_secs_f64()))?;
+            self.write_message(&format!(r#", "exec_time": {}"#, exec_time.0.as_secs_f64()))?;
         }
         if let Some(stdout) = stdout {
-            self.write_message(&*format!(r#", "stdout": "{}""#, EscapedString(stdout)))?;
+            self.write_message(&format!(r#", "stdout": "{}""#, EscapedString(stdout)))?;
         }
         if let Some(extra) = extra {
-            self.write_message(&*format!(r#", {extra}"#))?;
+            self.write_message(&format!(r#", {extra}"#))?;
         }
         self.writeln_message(" }")
     }
@@ -66,13 +66,13 @@ fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> i
         } else {
             String::new()
         };
-        self.writeln_message(&*format!(
+        self.writeln_message(&format!(
             r#"{{ "type": "suite", "event": "started", "test_count": {test_count}{shuffle_seed_json} }}"#
         ))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
-        self.writeln_message(&*format!(
+        self.writeln_message(&format!(
             r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
             EscapedString(desc.name.as_slice())
         ))
@@ -151,20 +151,20 @@ fn write_result(
                     mbps
                 );
 
-                self.writeln_message(&*line)
+                self.writeln_message(&line)
             }
         }
     }
 
     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
-        self.writeln_message(&*format!(
+        self.writeln_message(&format!(
             r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
             EscapedString(desc.name.as_slice())
         ))
     }
 
     fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
-        self.write_message(&*format!(
+        self.write_message(&format!(
             "{{ \"type\": \"suite\", \
              \"event\": \"{}\", \
              \"passed\": {}, \
index e6fb4f5707b35b17ef0c913d9880b2bee839ee9a..7a40ce33cb741bd3866738a074fa2ee1a594874a 100644 (file)
@@ -64,7 +64,7 @@ fn write_result(
     fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
         self.write_message("<testsuites>")?;
 
-        self.write_message(&*format!(
+        self.write_message(&format!(
             "<testsuite name=\"test\" package=\"test\" id=\"0\" \
              errors=\"0\" \
              failures=\"{}\" \
@@ -73,12 +73,12 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
              >",
             state.failed, state.total, state.ignored
         ))?;
-        for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
+        for (desc, result, duration) in std::mem::take(&mut self.results) {
             let (class_name, test_name) = parse_class_name(&desc);
             match result {
                 TestResult::TrIgnored => { /* no-op */ }
                 TestResult::TrFailed => {
-                    self.write_message(&*format!(
+                    self.write_message(&format!(
                         "<testcase classname=\"{}\" \
                          name=\"{}\" time=\"{}\">",
                         class_name,
@@ -90,19 +90,19 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
                 }
 
                 TestResult::TrFailedMsg(ref m) => {
-                    self.write_message(&*format!(
+                    self.write_message(&format!(
                         "<testcase classname=\"{}\" \
                          name=\"{}\" time=\"{}\">",
                         class_name,
                         test_name,
                         duration.as_secs_f64()
                     ))?;
-                    self.write_message(&*format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
+                    self.write_message(&format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
                     self.write_message("</testcase>")?;
                 }
 
                 TestResult::TrTimedFail => {
-                    self.write_message(&*format!(
+                    self.write_message(&format!(
                         "<testcase classname=\"{}\" \
                          name=\"{}\" time=\"{}\">",
                         class_name,
@@ -114,7 +114,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
                 }
 
                 TestResult::TrBench(ref b) => {
-                    self.write_message(&*format!(
+                    self.write_message(&format!(
                         "<testcase classname=\"benchmark::{}\" \
                          name=\"{}\" time=\"{}\" />",
                         class_name, test_name, b.ns_iter_summ.sum
@@ -122,7 +122,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
                 }
 
                 TestResult::TrOk => {
-                    self.write_message(&*format!(
+                    self.write_message(&format!(
                         "<testcase classname=\"{}\" \
                          name=\"{}\" time=\"{}\"/>",
                         class_name,
index 0299c8b543359adb3de118bb7f91436e0cf32879..247778e515f0dedd3f34840df9cdcae0c55bb2a3 100644 (file)
@@ -134,7 +134,7 @@ fn write_results(
 
         let mut results = Vec::new();
         let mut stdouts = String::new();
-        for &(ref f, ref stdout) in inputs {
+        for (f, stdout) in inputs {
             results.push(f.name.to_string());
             if !stdout.is_empty() {
                 stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
@@ -171,9 +171,9 @@ pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
         if let Some(test_mode) = desc.test_mode() {
-            self.write_plain(&format!("test {name} - {test_mode} ... "))?;
+            self.write_plain(format!("test {name} - {test_mode} ... "))?;
         } else {
-            self.write_plain(&format!("test {name} ... "))?;
+            self.write_plain(format!("test {name} ... "))?;
         }
 
         Ok(())
@@ -188,7 +188,7 @@ fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> i
         } else {
             String::new()
         };
-        self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
+        self.write_plain(format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -221,7 +221,7 @@ fn write_result(
             TestResult::TrIgnored => self.write_ignored(desc.ignore_message)?,
             TestResult::TrBench(ref bs) => {
                 self.write_bench()?;
-                self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?;
+                self.write_plain(format!(": {}", fmt_bench_samples(bs)))?;
             }
             TestResult::TrTimedFail => self.write_time_failed()?,
         }
@@ -231,7 +231,7 @@ fn write_result(
     }
 
     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
-        self.write_plain(&format!(
+        self.write_plain(format!(
             "test {} has been running for over {} seconds\n",
             desc.name,
             time::TEST_WARN_TIMEOUT_S
@@ -267,11 +267,11 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
             state.passed, state.failed, state.ignored, state.measured, state.filtered_out
         );
 
-        self.write_plain(&s)?;
+        self.write_plain(s)?;
 
         if let Some(ref exec_time) = state.exec_time {
             let time_str = format!("; finished in {exec_time}");
-            self.write_plain(&time_str)?;
+            self.write_plain(time_str)?;
         }
 
         self.write_plain("\n\n")?;
index 5dace8baef7f823054d29b93305922b4b8b2c667..0837ab16905130c18cd6c5086af909075c3d8feb 100644 (file)
@@ -70,7 +70,7 @@ pub fn write_short_result(
             // screen when dealing with line-buffered output (e.g., piping to
             // `stamp` in the rust CI).
             let out = format!(" {}/{}\n", self.test_count + 1, self.total_test_count);
-            self.write_plain(&out)?;
+            self.write_plain(out)?;
         }
 
         self.test_count += 1;
@@ -106,7 +106,7 @@ pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_plain("\nsuccesses:\n")?;
         let mut successes = Vec::new();
         let mut stdouts = String::new();
-        for &(ref f, ref stdout) in &state.not_failures {
+        for (f, stdout) in &state.not_failures {
             successes.push(f.name.to_string());
             if !stdout.is_empty() {
                 stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
@@ -132,7 +132,7 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_plain("\nfailures:\n")?;
         let mut failures = Vec::new();
         let mut fail_out = String::new();
-        for &(ref f, ref stdout) in &state.failures {
+        for (f, stdout) in &state.failures {
             failures.push(f.name.to_string());
             if !stdout.is_empty() {
                 fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
@@ -157,9 +157,9 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
         if let Some(test_mode) = desc.test_mode() {
-            self.write_plain(&format!("test {name} - {test_mode} ... "))?;
+            self.write_plain(format!("test {name} - {test_mode} ... "))?;
         } else {
-            self.write_plain(&format!("test {name} ... "))?;
+            self.write_plain(format!("test {name} ... "))?;
         }
 
         Ok(())
@@ -175,7 +175,7 @@ fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> i
         } else {
             String::new()
         };
-        self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
+        self.write_plain(format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -209,13 +209,13 @@ fn write_result(
                     self.write_test_name(desc)?;
                 }
                 self.write_bench()?;
-                self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
+                self.write_plain(format!(": {}\n", fmt_bench_samples(bs)))
             }
         }
     }
 
     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
-        self.write_plain(&format!(
+        self.write_plain(format!(
             "test {} has been running for over {} seconds\n",
             desc.name,
             time::TEST_WARN_TIMEOUT_S
@@ -245,11 +245,11 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
             state.passed, state.failed, state.ignored, state.measured, state.filtered_out
         );
 
-        self.write_plain(&s)?;
+        self.write_plain(s)?;
 
         if let Some(ref exec_time) = state.exec_time {
             let time_str = format!("; finished in {exec_time}");
-            self.write_plain(&time_str)?;
+            self.write_plain(time_str)?;
         }
 
         self.write_plain("\n\n")?;
index f6a41bbb88c852c8090e95b003e64379cc9759bb..30dc4ff855315d2c0f0bca55669d580e50d7f92e 100644 (file)
@@ -789,7 +789,7 @@ fn run_test_in_spawned_subprocess(
         }
     });
     let record_result2 = record_result.clone();
-    panic::set_hook(Box::new(move |info| record_result2(Some(&info))));
+    panic::set_hook(Box::new(move |info| record_result2(Some(info))));
     if let Err(message) = testfn() {
         panic!("{}", message);
     }
index 355859019714b5e17f86e3717ffae6d05fa022b1..67ba89410cd9974ed2cee345279100e6e2e68254 100644 (file)
@@ -149,7 +149,7 @@ fn reset(&mut self) -> io::Result<bool> {
         // are there any terminals that have color/attrs and not sgr0?
         // Try falling back to sgr, then op
         let cmd = match ["sgr0", "sgr", "op"].iter().find_map(|cap| self.ti.strings.get(*cap)) {
-            Some(op) => match expand(&op, &[], &mut Variables::new()) {
+            Some(op) => match expand(op, &[], &mut Variables::new()) {
                 Ok(cmd) => cmd,
                 Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
             },
@@ -180,12 +180,12 @@ pub(crate) fn new(out: T) -> Option<TerminfoTerminal<T>> {
     }
 
     fn dim_if_necessary(&self, color: color::Color) -> color::Color {
-        if color >= self.num_colors && color >= 8 && color < 16 { color - 8 } else { color }
+        if color >= self.num_colors && (8..16).contains(&color) { color - 8 } else { color }
     }
 
     fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
         match self.ti.strings.get(cmd) {
-            Some(cmd) => match expand(&cmd, params, &mut Variables::new()) {
+            Some(cmd) => match expand(cmd, params, &mut Variables::new()) {
                 Ok(s) => self.out.write_all(&s).and(Ok(true)),
                 Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)),
             },
index 0756c8374aa670d614c1d0c9b632af403e1fb22d..2815f6cfc77fe5058d0c77d7bf7f5be27002faef 100644 (file)
@@ -282,14 +282,14 @@ pub(crate) fn expand(
                 );
             }
             SetVar => {
-                if cur >= 'A' && cur <= 'Z' {
+                if cur.is_ascii_uppercase() {
                     if let Some(arg) = stack.pop() {
                         let idx = (cur as u8) - b'A';
                         vars.sta_va[idx as usize] = arg;
                     } else {
                         return Err("stack is empty".to_string());
                     }
-                } else if cur >= 'a' && cur <= 'z' {
+                } else if cur.is_ascii_lowercase() {
                     if let Some(arg) = stack.pop() {
                         let idx = (cur as u8) - b'a';
                         vars.dyn_va[idx as usize] = arg;
@@ -301,10 +301,10 @@ pub(crate) fn expand(
                 }
             }
             GetVar => {
-                if cur >= 'A' && cur <= 'Z' {
+                if cur.is_ascii_uppercase() {
                     let idx = (cur as u8) - b'A';
                     stack.push(vars.sta_va[idx as usize].clone());
-                } else if cur >= 'a' && cur <= 'z' {
+                } else if cur.is_ascii_lowercase() {
                     let idx = (cur as u8) - b'a';
                     stack.push(vars.dyn_va[idx as usize].clone());
                 } else {
index 68e181a6895799ef1bcbb5fe224f1354a4e74dea..87b91f34498a37085fd81b98fbbe8e60f798e54f 100644 (file)
@@ -22,7 +22,7 @@ pub(crate) fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
 
     if let Ok(dirs) = env::var("TERMINFO_DIRS") {
         for i in dirs.split(':') {
-            if i == "" {
+            if i.is_empty() {
                 dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
             } else {
                 dirs_to_search.push(PathBuf::from(i));
@@ -49,7 +49,7 @@ pub(crate) fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
     for mut p in dirs_to_search {
         if fs::metadata(&p).is_ok() {
             p.push(&first_char.to_string());
-            p.push(&term);
+            p.push(term);
             if fs::metadata(&p).is_ok() {
                 return Some(p);
             }
index 7c5b0d6c0f721072d0d13c40b3be84d529dee0e0..1da238e3e8c0fbd3fd1b5e7cf89a04a95263fed6 100644 (file)
@@ -33,7 +33,7 @@ pub fn calc_result<'a>(
 ) -> TestResult {
     let result = match (&desc.should_panic, task_result) {
         (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk,
-        (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
+        (&ShouldPanic::YesWithMessage(msg), Err(err)) => {
             let maybe_panic_str = err
                 .downcast_ref::<String>()
                 .map(|e| &**e)
@@ -52,7 +52,7 @@ pub fn calc_result<'a>(
                     r#"expected panic with string value,
  found non-string value: `{:?}`
      expected substring: `{:?}`"#,
-                    (**err).type_id(),
+                    (*err).type_id(),
                     msg
                 ))
             }
index 888afff7921d99f43698988cefa9acecdc41d76d..6f2e033095a37b9a7baacd89d3d4d6aae6401448 100644 (file)
@@ -47,7 +47,7 @@ pub fn as_slice(&self) -> &str {
         match *self {
             StaticTestName(s) => s,
             DynTestName(ref s) => s,
-            AlignedTestName(ref s, _) => &*s,
+            AlignedTestName(ref s, _) => s,
         }
     }
 
index 0fa11f3761ad79328b462f68537487ee99838cfb..036a35869a5b277568968990ac228a0fe28b80e5 100644 (file)
@@ -88,7 +88,7 @@ pub enum _Unwind_Context {}
     extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
 
 // FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in
-// the block are reexported in dylib build of libstd. This is needed when build rustc with
+// the block are reexported in dylib build of std. This is needed when build rustc with
 // feature `llvm-libunwind', as no other cdylib will provided those _Unwind_* symbols.
 // However the `link` attribute is duplicated multiple times and does not just export symbol,
 // a better way to manually export symbol would be another attribute like `#[export]`.
index 64b74ecc9defda3dbe4faaba34eaf5cd6b2440a4..4105fa5ec96006ac611439266af31ba70809084d 100644 (file)
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Several unsupported `./configure` options have been removed: `optimize`, `parallel-compiler`. These can still be enabled with `--set`, although it isn't recommended.
 - `remote-test-server`'s `verbose` argument has been removed in favor of the `--verbose` flag
 - `remote-test-server`'s `remote` argument has been removed in favor of the `--bind` flag. Use `--bind 0.0.0.0:12345` to replicate the behavior of the `remote` argument.
+- `x.py fmt` now formats only files modified between the merge-base of HEAD and the last commit in the master branch of the rust-lang repository and the current working directory. To restore old behaviour, use `x.py fmt .`. The check mode is not affected by this change. [#105702](https://github.com/rust-lang/rust/pull/105702)
 
 ### Non-breaking changes
 
index efe8ae3169fc2f9e4ca678f809a3d7aaf095bec4..4a0ba5925773e573e9862819ac10345f6c319cac 100644 (file)
@@ -36,6 +36,7 @@ dependencies = [
 name = "bootstrap"
 version = "0.0.0"
 dependencies = [
+ "build_helper",
  "cc",
  "cmake",
  "fd-lock",
@@ -70,6 +71,10 @@ dependencies = [
  "regex-automata",
 ]
 
+[[package]]
+name = "build_helper"
+version = "0.1.0"
+
 [[package]]
 name = "cc"
 version = "1.0.73"
index fafe82a9c128a44ea9307a635b3819282e42c8f1..22ceeca941e932872474ce0a3f549de91eece093 100644 (file)
@@ -30,6 +30,7 @@ path = "bin/sccache-plus-cl.rs"
 test = false
 
 [dependencies]
+build_helper = { path = "../tools/build_helper" }
 cmake = "0.1.38"
 fd-lock = "3.0.8"
 filetime = "0.2"
index 2d5018d934e2e27023b8ea25122517ce0c3a16f4..f3998e98583ecd32d564590389104cb35d95d3ff 100644 (file)
@@ -753,6 +753,9 @@ class RustBuild(object):
             target_features += ["-crt-static"]
         if target_features:
             env["RUSTFLAGS"] += " -C target-feature=" + (",".join(target_features))
+        target_linker = self.get_toml("linker", build_section)
+        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":
@@ -931,8 +934,7 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
 
-    help_triggered = (
-        '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+    help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
     try:
         bootstrap(help_triggered)
         if not help_triggered:
index 72d6a48b37ad759576267c77122047ab9a7df6fe..b54bf43262198e558353410c81d9ae201aeb020f 100644 (file)
@@ -13,7 +13,6 @@
 
 use crate::cache::{Cache, Interned, INTERNER};
 use crate::config::{SplitDebuginfo, TargetSelection};
-use crate::dist;
 use crate::doc;
 use crate::flags::{Color, Subcommand};
 use crate::install;
@@ -25,6 +24,7 @@
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
 use crate::EXTRA_CHECK_CFGS;
 use crate::{check, compile, Crate};
+use crate::{clean, dist};
 use crate::{Build, CLang, DocTests, GitRepo, Mode};
 
 pub use crate::Compiler;
@@ -96,6 +96,35 @@ impl RunConfig<'_> {
     pub fn build_triple(&self) -> TargetSelection {
         self.builder.build.build
     }
+
+    /// Return a list of crate names selected by `run.paths`.
+    pub fn cargo_crates_in_set(&self) -> Interned<Vec<String>> {
+        let mut crates = Vec::new();
+        for krate in &self.paths {
+            let path = krate.assert_single_path();
+            let crate_name = self.builder.crate_paths[&path.path];
+            crates.push(crate_name.to_string());
+        }
+        INTERNER.intern_list(crates)
+    }
+}
+
+/// A description of the crates in this set, suitable for passing to `builder.info`.
+///
+/// `crates` should be generated by [`RunConfig::cargo_crates_in_set`].
+pub fn crate_description(crates: &[impl AsRef<str>]) -> String {
+    if crates.is_empty() {
+        return "".into();
+    }
+
+    let mut descr = String::from(" {");
+    descr.push_str(crates[0].as_ref());
+    for krate in &crates[1..] {
+        descr.push_str(", ");
+        descr.push_str(krate.as_ref());
+    }
+    descr.push('}');
+    descr
 }
 
 struct StepDescription {
@@ -633,6 +662,7 @@ macro_rules! describe {
                 crate::toolstate::ToolStateCheck,
                 test::ExpandYamlAnchors,
                 test::Tidy,
+                test::TidySelfTest,
                 test::Ui,
                 test::RunPassValgrind,
                 test::MirOpt,
@@ -764,8 +794,9 @@ macro_rules! describe {
                 run::GenerateCopyright,
             ),
             Kind::Setup => describe!(setup::Profile),
-            // These commands either don't use paths, or they're special-cased in Build::build()
-            Kind::Clean | Kind::Format => vec![],
+            Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
+            // special-cased in Build::build()
+            Kind::Format => vec![],
         }
     }
 
@@ -827,14 +858,12 @@ pub fn new(build: &Build) -> Builder<'_> {
             Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
             Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
             Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
+            Subcommand::Clean { ref paths, .. } => (Kind::Clean, &paths[..]),
             Subcommand::Format { .. } => (Kind::Format, &[][..]),
             Subcommand::Setup { profile: ref path } => (
                 Kind::Setup,
                 path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
             ),
-            Subcommand::Clean { .. } => {
-                panic!()
-            }
         };
 
         Self::new_internal(build, kind, paths.to_owned())
@@ -1077,6 +1106,62 @@ fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         None
     }
 
+    /// Like `cargo`, but only passes flags that are valid for all commands.
+    pub fn bare_cargo(
+        &self,
+        compiler: Compiler,
+        mode: Mode,
+        target: TargetSelection,
+        cmd: &str,
+    ) -> Command {
+        let mut cargo = Command::new(&self.initial_cargo);
+        // Run cargo from the source root so it can find .cargo/config.
+        // This matters when using vendoring and the working directory is outside the repository.
+        cargo.current_dir(&self.src);
+
+        let out_dir = self.stage_out(compiler, mode);
+        cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
+
+        // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
+        // from out of tree it shouldn't matter, since x.py is only used for
+        // building in-tree.
+        let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
+        match self.build.config.color {
+            Color::Always => {
+                cargo.arg("--color=always");
+                for log in &color_logs {
+                    cargo.env(log, "always");
+                }
+            }
+            Color::Never => {
+                cargo.arg("--color=never");
+                for log in &color_logs {
+                    cargo.env(log, "never");
+                }
+            }
+            Color::Auto => {} // nothing to do
+        }
+
+        if cmd != "install" {
+            cargo.arg("--target").arg(target.rustc_target_arg());
+        } else {
+            assert_eq!(target, compiler.host);
+        }
+
+        if self.config.rust_optimize {
+            // FIXME: cargo bench/install do not accept `--release`
+            if cmd != "bench" && cmd != "install" {
+                cargo.arg("--release");
+            }
+        }
+
+        // Remove make-related flags to ensure Cargo can correctly set things up
+        cargo.env_remove("MAKEFLAGS");
+        cargo.env_remove("MFLAGS");
+
+        cargo
+    }
+
     /// Prepares an invocation of `cargo` to be run.
     ///
     /// This will create a `Command` that represents a pending execution of
@@ -1092,11 +1177,8 @@ pub fn cargo(
         target: TargetSelection,
         cmd: &str,
     ) -> Cargo {
-        let mut cargo = Command::new(&self.initial_cargo);
+        let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
         let out_dir = self.stage_out(compiler, mode);
-        // Run cargo from the source root so it can find .cargo/config.
-        // This matters when using vendoring and the working directory is outside the repository.
-        cargo.current_dir(&self.src);
 
         // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
         // so we need to explicitly clear out if they've been updated.
@@ -1121,8 +1203,6 @@ pub fn cargo(
             self.clear_if_dirty(&my_out, &rustdoc);
         }
 
-        cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
-
         let profile_var = |name: &str| {
             let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
             format!("CARGO_PROFILE_{}_{}", profile, name)
@@ -1135,32 +1215,6 @@ pub fn cargo(
             cargo.env("REAL_LIBRARY_PATH", e);
         }
 
-        // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
-        // from out of tree it shouldn't matter, since x.py is only used for
-        // building in-tree.
-        let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
-        match self.build.config.color {
-            Color::Always => {
-                cargo.arg("--color=always");
-                for log in &color_logs {
-                    cargo.env(log, "always");
-                }
-            }
-            Color::Never => {
-                cargo.arg("--color=never");
-                for log in &color_logs {
-                    cargo.env(log, "never");
-                }
-            }
-            Color::Auto => {} // nothing to do
-        }
-
-        if cmd != "install" {
-            cargo.arg("--target").arg(target.rustc_target_arg());
-        } else {
-            assert_eq!(target, compiler.host);
-        }
-
         // Set a flag for `check`/`clippy`/`fix`, so that certain build
         // scripts can do less work (i.e. not building/requiring LLVM).
         if cmd == "check" || cmd == "clippy" || cmd == "fix" {
@@ -1341,9 +1395,6 @@ pub fn cargo(
         }
 
         cargo.arg("-j").arg(self.jobs().to_string());
-        // Remove make-related flags to ensure Cargo can correctly set things up
-        cargo.env_remove("MAKEFLAGS");
-        cargo.env_remove("MFLAGS");
 
         // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
         // Force cargo to output binaries with disambiguating hashes in the name
@@ -1827,13 +1878,6 @@ pub fn cargo(
             }
         }
 
-        if self.config.rust_optimize {
-            // FIXME: cargo bench/install do not accept `--release`
-            if cmd != "bench" && cmd != "install" {
-                cargo.arg("--release");
-            }
-        }
-
         if self.config.locked_deps {
             cargo.arg("--locked");
         }
index 2e1bd8d6d1f6db817547866633ae240c7dd9d685..b203ecd3844b039d11358abc156f6d7b427a8be6 100644 (file)
@@ -99,19 +99,13 @@ fn run(self, builder: &Builder<'_>) {
             cargo_subcommand(builder.kind),
         );
         std_cargo(builder, target, compiler.stage, &mut cargo);
+        cargo.args(args(builder));
 
         builder.info(&format!(
-            "Checking stage{} std artifacts ({} -> {})",
+            "Checking stage{} library artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(
-            builder,
-            cargo,
-            args(builder),
-            &libstd_stamp(builder, compiler, target),
-            vec![],
-            true,
-        );
+        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false);
 
         // We skip populating the sysroot in non-zero stage because that'll lead
         // to rlib/rmeta conflicts if std gets built during this session.
@@ -155,18 +149,19 @@ fn run(self, builder: &Builder<'_>) {
         for krate in builder.in_tree_crates("test", Some(target)) {
             cargo.arg("-p").arg(krate.name);
         }
+        cargo.args(args(builder));
 
         builder.info(&format!(
-            "Checking stage{} std test/bench/example targets ({} -> {})",
+            "Checking stage{} library test/bench/example targets ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
         run_cargo(
             builder,
             cargo,
-            args(builder),
             &libstd_test_stamp(builder, compiler, target),
             vec![],
             true,
+            false,
         );
     }
 }
@@ -231,19 +226,13 @@ fn run(self, builder: &Builder<'_>) {
         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
             cargo.arg("-p").arg(krate.name);
         }
+        cargo.args(args(builder));
 
         builder.info(&format!(
             "Checking stage{} compiler artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(
-            builder,
-            cargo,
-            args(builder),
-            &librustc_stamp(builder, compiler, target),
-            vec![],
-            true,
-        );
+        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false);
 
         let libdir = builder.sysroot_libdir(compiler, target);
         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
@@ -290,6 +279,7 @@ fn run(self, builder: &Builder<'_>) {
             .arg("--manifest-path")
             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
         rustc_cargo_env(builder, &mut cargo, target);
+        cargo.args(args(builder));
 
         builder.info(&format!(
             "Checking stage{} {} artifacts ({} -> {})",
@@ -299,10 +289,10 @@ fn run(self, builder: &Builder<'_>) {
         run_cargo(
             builder,
             cargo,
-            args(builder),
             &codegen_backend_stamp(builder, compiler, target, backend),
             vec![],
             true,
+            false,
         );
     }
 }
@@ -355,11 +345,13 @@ fn run(self, builder: &Builder<'_>) {
             cargo.arg("--benches");
         }
 
+        cargo.args(args(builder));
+
         builder.info(&format!(
             "Checking stage{} {} artifacts ({} -> {})",
             compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
         ));
-        run_cargo(builder, cargo, args(builder), &stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false);
 
         /// Cargo's output path in a given stage, compiled by a particular
         /// compiler for the specified target.
@@ -413,6 +405,8 @@ fn run(self, builder: &Builder<'_>) {
                     cargo.arg("--all-targets");
                 }
 
+                cargo.args(args(builder));
+
                 // Enable internal lints for clippy and rustdoc
                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
@@ -428,10 +422,10 @@ fn run(self, builder: &Builder<'_>) {
                 run_cargo(
                     builder,
                     cargo,
-                    args(builder),
                     &stamp(builder, compiler, target),
                     vec![],
                     true,
+                    false,
                 );
 
                 /// Cargo's output path in a given stage, compiled by a particular
index 069f3d6acf158937d278a13a277bec4e90c762c6..468efc1114c43f3ff8e6735b4e87313a8f5739bb 100644 (file)
@@ -9,10 +9,81 @@
 use std::io::{self, ErrorKind};
 use std::path::Path;
 
+use crate::builder::{crate_description, Builder, RunConfig, ShouldRun, Step};
+use crate::cache::Interned;
 use crate::util::t;
-use crate::Build;
+use crate::{Build, Compiler, Mode, Subcommand};
 
-pub fn clean(build: &Build, all: bool) {
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CleanAll {}
+
+impl Step for CleanAll {
+    const DEFAULT: bool = true;
+    type Output = ();
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(CleanAll {})
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let Subcommand::Clean { all, .. } = builder.config.cmd else { unreachable!("wrong subcommand?") };
+        clean_default(builder.build, all)
+    }
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never() // handled by DEFAULT
+    }
+}
+
+macro_rules! clean_crate_tree {
+    ( $( $name:ident, $mode:path, $root_crate:literal);+ $(;)? ) => { $(
+        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+        pub struct $name {
+            compiler: Compiler,
+            crates: Interned<Vec<String>>,
+        }
+
+        impl Step for $name {
+            type Output = ();
+
+            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+                let crates = run.builder.in_tree_crates($root_crate, None);
+                run.crates(crates)
+            }
+
+            fn make_run(run: RunConfig<'_>) {
+                let builder = run.builder;
+                let compiler = builder.compiler(builder.top_stage, run.target);
+                builder.ensure(Self { crates: run.cargo_crates_in_set(), compiler });
+            }
+
+            fn run(self, builder: &Builder<'_>) -> Self::Output {
+                let compiler = self.compiler;
+                let target = compiler.host;
+                let mut cargo = builder.bare_cargo(compiler, $mode, target, "clean");
+                for krate in &*self.crates {
+                    cargo.arg(krate);
+                }
+
+                builder.info(&format!(
+                    "Cleaning{} stage{} {} artifacts ({} -> {})",
+                    crate_description(&self.crates), compiler.stage, stringify!($name).to_lowercase(), &compiler.host, target,
+                ));
+
+                // NOTE: doesn't use `run_cargo` because we don't want to save a stamp file,
+                // and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept.
+                builder.run(&mut cargo);
+            }
+        }
+    )+ }
+}
+
+clean_crate_tree! {
+    Rustc, Mode::Rustc, "rustc-main";
+    Std, Mode::Std, "test";
+}
+
+fn clean_default(build: &Build, all: bool) {
     rm_rf("tmp".as_ref());
 
     if all {
@@ -21,6 +92,7 @@ pub fn clean(build: &Build, all: bool) {
         rm_rf(&build.out.join("tmp"));
         rm_rf(&build.out.join("dist"));
         rm_rf(&build.out.join("bootstrap"));
+        rm_rf(&build.out.join("rustfmt.stamp"));
 
         for host in &build.hosts {
             let entries = match build.out.join(host.triple).read_dir() {
index 0e3bbad9909eb243c7a02618bc6d0332db49c07c..147ded3a9eed7c13ee41b09b2117bf6100e7b56f 100644 (file)
@@ -18,6 +18,7 @@
 
 use serde::Deserialize;
 
+use crate::builder::crate_description;
 use crate::builder::Cargo;
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
@@ -46,17 +47,6 @@ pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
     }
 }
 
-/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
-fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> {
-    let mut crates = Vec::new();
-    for krate in &run.paths {
-        let path = krate.assert_single_path();
-        let crate_name = run.builder.crate_paths[&path.path];
-        crates.push(format!("-p={crate_name}"));
-    }
-    INTERNER.intern_list(crates)
-}
-
 impl Step for Std {
     type Output = ();
     const DEFAULT: bool = true;
@@ -76,7 +66,7 @@ fn make_run(run: RunConfig<'_>) {
         // Build all crates anyway, as if they hadn't passed the other args.
         let has_library =
             run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
-        let crates = if has_library { Default::default() } else { build_crates_in_set(&run) };
+        let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() };
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
@@ -121,7 +111,10 @@ fn run(self, builder: &Builder<'_>) {
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         if compiler_to_use != compiler {
             builder.ensure(Std::new(compiler_to_use, target));
-            builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target));
+            builder.info(&format!(
+                "Uplifting stage1 library ({} -> {})",
+                compiler_to_use.host, target
+            ));
 
             // Even if we're not building std this stage, the new sysroot must
             // still contain the third party objects needed by various targets.
@@ -137,18 +130,24 @@ fn run(self, builder: &Builder<'_>) {
 
         let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build");
         std_cargo(builder, target, compiler.stage, &mut cargo);
+        for krate in &*self.crates {
+            cargo.arg("-p").arg(krate);
+        }
 
         builder.info(&format!(
-            "Building stage{} std artifacts ({} -> {})",
-            compiler.stage, &compiler.host, target
+            "Building{} stage{} library artifacts ({} -> {})",
+            crate_description(&self.crates),
+            compiler.stage,
+            &compiler.host,
+            target,
         ));
         run_cargo(
             builder,
             cargo,
-            self.crates.to_vec(),
             &libstd_stamp(builder, compiler, target),
             target_deps,
             false,
+            false,
         );
 
         builder.ensure(StdLink::from_std(
@@ -436,7 +435,7 @@ fn run(self, builder: &Builder<'_>) {
         let target_compiler = self.target_compiler;
         let target = self.target;
         builder.info(&format!(
-            "Copying stage{} std from stage{} ({} -> {} / {})",
+            "Copying stage{} library from stage{} ({} -> {} / {})",
             target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target
         ));
         let libdir = builder.sysroot_libdir(target_compiler, target);
@@ -603,7 +602,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let crates = build_crates_in_set(&run);
+        let crates = run.cargo_crates_in_set();
         run.builder.ensure(Rustc {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
@@ -702,7 +701,8 @@ fn run(self, builder: &Builder<'_>) {
             ));
         }
 
-        // cfg(bootstrap): remove if condition once the bootstrap compiler supports dylib LTO
+        // We currently don't support cross-crate LTO in stage0. This also isn't hugely necessary
+        // and may just be a time sink.
         if compiler.stage != 0 {
             match builder.config.rust_lto {
                 RustcLto::Thin | RustcLto::Fat => {
@@ -724,17 +724,24 @@ fn run(self, builder: &Builder<'_>) {
             }
         }
 
+        for krate in &*self.crates {
+            cargo.arg("-p").arg(krate);
+        }
+
         builder.info(&format!(
-            "Building stage{} compiler artifacts ({} -> {})",
-            compiler.stage, &compiler.host, target
+            "Building{} stage{} compiler artifacts ({} -> {})",
+            crate_description(&self.crates),
+            compiler.stage,
+            &compiler.host,
+            target,
         ));
         run_cargo(
             builder,
             cargo,
-            self.crates.to_vec(),
             &librustc_stamp(builder, compiler, target),
             vec![],
             false,
+            true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
         );
 
         builder.ensure(RustcLink::from_rustc(
@@ -991,7 +998,7 @@ fn run(self, builder: &Builder<'_>) {
             "Building stage{} codegen backend {} ({} -> {})",
             compiler.stage, backend, &compiler.host, target
         ));
-        let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
+        let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false);
         if builder.config.dry_run() {
             return;
         }
@@ -1415,10 +1422,10 @@ pub fn add_to_sysroot(
 pub fn run_cargo(
     builder: &Builder<'_>,
     cargo: Cargo,
-    tail_args: Vec<String>,
     stamp: &Path,
     additional_target_deps: Vec<(PathBuf, DependencyType)>,
     is_check: bool,
+    rlib_only_metadata: bool,
 ) -> Vec<PathBuf> {
     if builder.config.dry_run() {
         return Vec::new();
@@ -1441,7 +1448,7 @@ pub fn run_cargo(
     // files we need to probe for later.
     let mut deps = Vec::new();
     let mut toplevel = Vec::new();
-    let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| {
+    let ok = stream_cargo(builder, cargo, &mut |msg| {
         let (filenames, crate_types) = match msg {
             CargoMessage::CompilerArtifact {
                 filenames,
@@ -1452,13 +1459,35 @@ pub fn run_cargo(
         };
         for filename in filenames {
             // Skip files like executables
-            if !(filename.ends_with(".rlib")
-                || filename.ends_with(".lib")
+            let mut keep = false;
+            if filename.ends_with(".lib")
                 || filename.ends_with(".a")
                 || is_debug_info(&filename)
                 || is_dylib(&filename)
-                || (is_check && filename.ends_with(".rmeta")))
             {
+                // Always keep native libraries, rust dylibs and debuginfo
+                keep = true;
+            }
+            if is_check && filename.ends_with(".rmeta") {
+                // During check builds we need to keep crate metadata
+                keep = true;
+            } else if rlib_only_metadata {
+                if filename.contains("jemalloc_sys") || filename.contains("rustc_smir") {
+                    // jemalloc_sys and rustc_smir are not linked into librustc_driver.so,
+                    // so we need to distribute them as rlib to be able to use them.
+                    keep |= filename.ends_with(".rlib");
+                } else {
+                    // Distribute the rest of the rustc crates as rmeta files only to reduce
+                    // the tarball sizes by about 50%. The object files are linked into
+                    // librustc_driver.so, so it is still possible to link against them.
+                    keep |= filename.ends_with(".rmeta");
+                }
+            } else {
+                // In all other cases keep all rlibs
+                keep |= filename.ends_with(".rlib");
+            }
+
+            if !keep {
                 continue;
             }
 
@@ -1556,7 +1585,6 @@ pub fn run_cargo(
 pub fn stream_cargo(
     builder: &Builder<'_>,
     cargo: Cargo,
-    tail_args: Vec<String>,
     cb: &mut dyn FnMut(CargoMessage<'_>),
 ) -> bool {
     let mut cargo = Command::from(cargo);
@@ -1576,10 +1604,6 @@ pub fn stream_cargo(
     }
     cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped());
 
-    for arg in tail_args {
-        cargo.arg(arg);
-    }
-
     builder.verbose(&format!("running: {:?}", cargo));
     let mut child = match cargo.spawn() {
         Ok(child) => child,
index 6b139decb555193f3990962a6812a217867c281c..31cc4aa57bbea45170f4ff339e424528c1edee5c 100755 (executable)
@@ -405,7 +405,9 @@ if 'target' in config:
         configured_targets.append(target)
 for target in configured_targets:
     targets[target] = sections['target'][:]
-    targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target))
+    # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
+    # Avoid using quotes unless it's necessary.
+    targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
 
 
 def is_number(value):
index 340aa78ebf9b5b71a45fca0b2b7bcfa5fc3f6c6d..68215790bed177e3fdd3b4376da622b612bc689a 100644 (file)
@@ -2067,6 +2067,9 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
 
         builder.ensure(crate::native::Llvm { target });
 
+        // We want to package `lld` to use it with `download-ci-llvm`.
+        builder.ensure(crate::native::Lld { target });
+
         let src_bindir = builder.llvm_out(target).join("bin");
         // If updating this list, you likely want to change
         // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
index 5838049aa5c79d96d240e0a11b2e3dbc5e74e02d..9bad9046ecc2c4fed4a122d5d2a60ccf2adda4c1 100644 (file)
@@ -12,6 +12,7 @@
 use std::io;
 use std::path::{Path, PathBuf};
 
+use crate::builder::crate_description;
 use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
@@ -506,7 +507,11 @@ fn run(self, builder: &Builder<'_>) {
         // Look for library/std, library/core etc in the `x.py doc` arguments and
         // open the corresponding rendered docs.
         for requested_crate in requested_crates {
-            if STD_PUBLIC_CRATES.iter().any(|k| *k == requested_crate.as_str()) {
+            if requested_crate == "library" {
+                // For `x.py doc library --open`, open `std` by default.
+                let index = out.join("std").join("index.html");
+                builder.open_in_browser(index);
+            } else if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
                 let index = out.join(requested_crate).join("index.html");
                 builder.open_in_browser(index);
             }
@@ -554,7 +559,8 @@ fn doc_std(
     requested_crates: &[String],
 ) {
     builder.info(&format!(
-        "Documenting stage{} std ({}) in {} format",
+        "Documenting{} stage{} library ({}) in {} format",
+        crate_description(requested_crates),
         stage,
         target,
         format.as_str()
index d19a1ae95cf145dcc44f488a8facbb356f12a35a..94630e40f3c4ca5a68e3bd5e149fa190fd265b15 100644 (file)
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/102790
+Last change is for: https://github.com/rust-lang/rust/pull/104748
index 851cb5ecf4c2694ee7c77b7b97e4bd92a1c7d6a4..2c6d201d18fbeacc697c03f990d8770d04bfa8ff 100644 (file)
@@ -130,6 +130,7 @@ pub enum Subcommand {
         test_args: Vec<String>,
     },
     Clean {
+        paths: Vec<PathBuf>,
         all: bool,
     },
     Dist {
@@ -351,22 +352,32 @@ pub fn parse(args: &[String]) -> Flags {
 
         // fn usage()
         let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
-            let config = Config::parse(&["setup".to_string()]);
-            let build = Build::new(config);
-            let paths = Builder::get_help(&build, subcommand);
-
             println!("{}", opts.usage(subcommand_help));
-            if let Some(s) = paths {
-                if verbose {
+            if verbose {
+                // We have an unfortunate situation here: some Steps use `builder.in_tree_crates` to determine their paths.
+                // To determine those crates, we need to run `cargo metadata`, which means we need all submodules to be checked out.
+                // That takes a while to run, so only do it when paths were explicitly requested, not on all CLI errors.
+                // `Build::new` won't load submodules for the `setup` command.
+                let cmd = if verbose {
+                    println!("note: updating submodules before printing available paths");
+                    "build"
+                } else {
+                    "setup"
+                };
+                let config = Config::parse(&[cmd.to_string()]);
+                let build = Build::new(config);
+                let paths = Builder::get_help(&build, subcommand);
+
+                if let Some(s) = paths {
                     println!("{}", s);
                 } else {
-                    println!(
-                        "Run `./x.py {} -h -v` to see a list of available paths.",
-                        subcommand.as_str()
-                    );
+                    panic!("No paths available for subcommand `{}`", subcommand.as_str());
                 }
-            } else if verbose {
-                panic!("No paths available for subcommand `{}`", subcommand.as_str());
+            } else {
+                println!(
+                    "Run `./x.py {} -h -v` to see a list of available paths.",
+                    subcommand.as_str()
+                );
             }
             crate::detail_exit(exit_code);
         };
@@ -601,14 +612,7 @@ pub fn parse(args: &[String]) -> Flags {
                 open: matches.opt_present("open"),
                 json: matches.opt_present("json"),
             },
-            Kind::Clean => {
-                if !paths.is_empty() {
-                    println!("\nclean does not take a path argument\n");
-                    usage(1, &opts, verbose, &subcommand_help);
-                }
-
-                Subcommand::Clean { all: matches.opt_present("all") }
-            }
+            Kind::Clean => Subcommand::Clean { all: matches.opt_present("all"), paths },
             Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
             Kind::Dist => Subcommand::Dist { paths },
             Kind::Install => Subcommand::Install { paths },
index b2f6afead798088e12ae27425b354540ea6c302b..bfc57a85cdb42bdd106098ae9e4fc3bc707904de 100644 (file)
@@ -1,7 +1,8 @@
 //! Runs rustfmt on the repository.
 
 use crate::builder::Builder;
-use crate::util::{output, t};
+use crate::util::{output, output_result, program_out_of_date, t};
+use build_helper::git::updated_master_branch;
 use ignore::WalkBuilder;
 use std::collections::VecDeque;
 use std::path::{Path, PathBuf};
@@ -44,6 +45,60 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
     }
 }
 
+fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> {
+    let stamp_file = build.out.join("rustfmt.stamp");
+
+    let mut cmd = Command::new(match build.initial_rustfmt() {
+        Some(p) => p,
+        None => return None,
+    });
+    cmd.arg("--version");
+    let output = match cmd.output() {
+        Ok(status) => status,
+        Err(_) => return None,
+    };
+    if !output.status.success() {
+        return None;
+    }
+    Some((String::from_utf8(output.stdout).unwrap(), stamp_file))
+}
+
+/// Return whether the format cache can be reused.
+fn verify_rustfmt_version(build: &Builder<'_>) -> bool {
+    let Some((version, stamp_file)) = get_rustfmt_version(build) else {return false;};
+    !program_out_of_date(&stamp_file, &version)
+}
+
+/// Updates the last rustfmt version used
+fn update_rustfmt_version(build: &Builder<'_>) {
+    let Some((version, stamp_file)) = get_rustfmt_version(build) else {return;};
+    t!(std::fs::write(stamp_file, version))
+}
+
+/// Returns the Rust files modified between the `merge-base` of HEAD and
+/// rust-lang/master and what is now on the disk.
+///
+/// Returns `None` if all files should be formatted.
+fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
+    let Ok(updated_master) = updated_master_branch(Some(&build.config.src)) else { return Ok(None); };
+
+    if !verify_rustfmt_version(build) {
+        return Ok(None);
+    }
+
+    let merge_base =
+        output_result(build.config.git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
+    Ok(Some(
+        output_result(
+            build.config.git().arg("diff-index").arg("--name-only").arg(merge_base.trim()),
+        )?
+        .lines()
+        .map(|s| s.trim().to_owned())
+        .filter(|f| Path::new(f).extension().map_or(false, |ext| ext == "rs"))
+        .collect(),
+    ))
+}
+
 #[derive(serde::Deserialize)]
 struct RustfmtConfig {
     ignore: Vec<String>,
@@ -78,6 +133,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         Ok(status) => status.success(),
         Err(_) => false,
     };
+
+    let mut paths = paths.to_vec();
+
     if git_available {
         let in_working_tree = match build
             .config
@@ -110,12 +168,32 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                 // preventing the latter from being formatted.
                 ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
             }
+            if !check && paths.is_empty() {
+                match get_modified_rs_files(build) {
+                    Ok(Some(files)) => {
+                        for file in files {
+                            println!("formatting modified file {file}");
+                            ignore_fmt.add(&format!("/{file}")).expect(&file);
+                        }
+                    }
+                    Ok(None) => {}
+                    Err(err) => {
+                        println!(
+                            "WARN: Something went wrong when running git commands:\n{err}\n\
+                            Falling back to formatting all files."
+                        );
+                        // Something went wrong when getting the version. Just format all the files.
+                        paths.push(".".into());
+                    }
+                }
+            }
         } else {
             println!("Not in git tree. Skipping git-aware format checks");
         }
     } else {
         println!("Could not find usable git. Skipping git-aware format checks");
     }
+
     let ignore_fmt = ignore_fmt.build().unwrap();
 
     let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
@@ -187,4 +265,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     drop(tx);
 
     thread.join().unwrap();
+    if !check {
+        update_rustfmt_version(build);
+    }
 }
index f84fcd21cfcfeacb7be2938ed3e5239377822a48..d44b96cfb991ece07a53944f225a0624737b2921 100644 (file)
 use std::process::Command;
 use std::str;
 
+use build_helper::ci::CiEnv;
 use channel::GitInfo;
 use config::{DryRun, Target};
 use filetime::FileTime;
 use crate::builder::Kind;
 use crate::config::{LlvmLibunwind, TargetSelection};
 use crate::util::{
-    exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, CiEnv,
+    exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
 };
 
 mod bolt;
@@ -727,10 +728,6 @@ pub fn build(&mut self) {
             return format::format(&builder::Builder::new(&self), *check, &paths);
         }
 
-        if let Subcommand::Clean { all } = self.config.cmd {
-            return clean::clean(self, all);
-        }
-
         // Download rustfmt early so that it can be used in rust-analyzer configs.
         let _ = &builder::Builder::new(&self).initial_rustfmt();
 
@@ -1400,7 +1397,10 @@ fn in_tree_crates(&self, root: &str, target: Option<TargetSelection>) -> Vec<&Cr
         let mut list = vec![INTERNER.intern_str(root)];
         let mut visited = HashSet::new();
         while let Some(krate) = list.pop() {
-            let krate = &self.crates[&krate];
+            let krate = self
+                .crates
+                .get(&krate)
+                .unwrap_or_else(|| panic!("metadata missing for {krate}: {:?}", self.crates));
             ret.push(krate);
             for dep in &krate.deps {
                 if !self.crates.contains_key(dep) {
index 4e503dfe864e2937eca0461125effb8147739ff1..89bb2b770f90deba19893bf5b5a193b887a97ffa 100644 (file)
@@ -24,6 +24,8 @@
 use crate::util::{self, exe, output, t, up_to_date};
 use crate::{CLang, GitRepo};
 
+use build_helper::ci::CiEnv;
+
 #[derive(Clone)]
 pub struct LlvmResult {
     /// Path to llvm-config binary.
@@ -63,13 +65,13 @@ fn push_all(&mut self, s: impl AsRef<OsStr>) {
     }
 }
 
-// This returns whether we've already previously built LLVM.
-//
-// It's used to avoid busting caches during x.py check -- if we've already built
-// LLVM, it's fine for us to not try to avoid doing so.
-//
-// This will return the llvm-config if it can get it (but it will not build it
-// if not).
+/// This returns whether we've already previously built LLVM.
+///
+/// It's used to avoid busting caches during x.py check -- if we've already built
+/// LLVM, it's fine for us to not try to avoid doing so.
+///
+/// This will return the llvm-config if it can get it (but it will not build it
+/// if not).
 pub fn prebuilt_llvm_config(
     builder: &Builder<'_>,
     target: TargetSelection,
@@ -217,7 +219,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
         return false;
     }
 
-    if crate::util::CiEnv::is_ci() {
+    if CiEnv::is_ci() {
         // We assume we have access to git, so it's okay to unconditionally pass
         // `true` here.
         let llvm_sha = detect_llvm_sha(config, true);
@@ -823,8 +825,21 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         }
         let target = self.target;
 
-        let LlvmResult { llvm_config, llvm_cmake_dir } =
-            builder.ensure(Llvm { target: self.target });
+        let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
+
+        // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path
+        // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin`
+        // subfolder. We check if that's the case, and if LLD's binary already exists there next to
+        // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source.
+        let ci_llvm_bin = llvm_config.parent().unwrap();
+        if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" {
+            let lld_path = ci_llvm_bin.join(exe("lld", target));
+            if lld_path.exists() {
+                // The following steps copying `lld` as `rust-lld` to the sysroot, expect it in the
+                // `bin` subfolder of this step's out dir.
+                return ci_llvm_bin.parent().unwrap().to_path_buf();
+            }
+        }
 
         let out_dir = builder.lld_out(target);
         let done_stamp = out_dir.join("lld-finished-building");
@@ -1072,12 +1087,12 @@ fn supported_sanitizers(
 
     match &*target.triple {
         "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
-        "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
+        "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
         "aarch64-unknown-linux-gnu" => {
             common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
         }
         "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
-        "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
+        "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
         "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]),
         "x86_64-unknown-netbsd" => {
             common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"])
index 05de51f8cc57933b886fb6a7b1d2436e4c728316..e0280854541a0d95b6979a84b2157c8e1966e55f 100644 (file)
@@ -105,6 +105,7 @@ fn make_run(run: RunConfig<'_>) {
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let mut cmd = builder.tool_cmd(Tool::BumpStage0);
+        cmd.args(builder.config.cmd.args());
         builder.run(&mut cmd);
     }
 }
index cd360cbef9654b3108d2c1100f6613c5039f6278..ca4feac6fac70f21e9bbc0accdcc4aee9e910074 100644 (file)
@@ -351,7 +351,7 @@ fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
     Ok(template)
 }
 
-// install a git hook to automatically run tidy --bless, if they want
+// 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| {
         assert!(output.status.success(), "failed to run `git`");
@@ -367,7 +367,7 @@ fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     println!();
     println!(
         "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
-If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
+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."
     );
index 0d9c22e210f9d3ffd7de346614eb4b2f9c45451f..ea906be7e3ac255f58fc0d1ddb780bc82b8edc60 100644 (file)
@@ -11,6 +11,7 @@
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 
+use crate::builder::crate_description;
 use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::Interned;
 use crate::compile;
@@ -1048,7 +1049,7 @@ fn run(self, builder: &Builder<'_>) {
                 if entry.file_name() == "link_to_definition" {
                     cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition");
                 } else if entry.file_name() == "scrape_examples" {
-                    cargo.arg("-Zrustdoc-scrape-examples=examples");
+                    cargo.arg("-Zrustdoc-scrape-examples");
                 }
                 builder.run(&mut cargo);
             }
@@ -1142,6 +1143,40 @@ fn make_run(run: RunConfig<'_>) {
     }
 }
 
+/// Runs tidy's own tests.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct TidySelfTest;
+
+impl Step for TidySelfTest {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("tidyselftest")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(TidySelfTest);
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let bootstrap_host = builder.config.build;
+        let compiler = builder.compiler(0, bootstrap_host);
+        let cargo = tool::prepare_tool_cargo(
+            builder,
+            compiler,
+            Mode::ToolBootstrap,
+            bootstrap_host,
+            "test",
+            "src/tools/tidy",
+            SourceType::InTree,
+            &[],
+        );
+        try_run(builder, &mut cargo.into());
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct ExpandYamlAnchors;
 
@@ -2154,8 +2189,12 @@ fn run(self, builder: &Builder<'_>) {
         }
 
         builder.info(&format!(
-            "{} {:?} stage{} ({} -> {})",
-            test_kind, self.crates, compiler.stage, &compiler.host, target
+            "{}{} stage{} ({} -> {})",
+            test_kind,
+            crate_description(&self.crates),
+            compiler.stage,
+            &compiler.host,
+            target
         ));
         let _time = util::timeit(&builder);
         try_run(builder, &mut cargo.into());
index 24b033cc0dc5eb4f6e63104efc065a507d35a114..63026bd44d475277d388b9a3b8d37d237a0e8842 100644 (file)
@@ -72,7 +72,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
 
         builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
         let mut duplicates = Vec::new();
-        let is_expected = compile::stream_cargo(builder, cargo, vec![], &mut |msg| {
+        let is_expected = compile::stream_cargo(builder, cargo, &mut |msg| {
             // Only care about big things like the RLS/Cargo for now
             match tool {
                 "rls" | "cargo" | "clippy-driver" | "miri" | "rustfmt" => {}
index 58220783228b2883fae9ba5ca03d646048e41964..93e53d383cd39daa00485a0f46dd9277056d918d 100644 (file)
@@ -255,35 +255,6 @@ pub enum CiEnv {
     GitHubActions,
 }
 
-impl CiEnv {
-    /// Obtains the current CI environment.
-    pub fn current() -> CiEnv {
-        if env::var("TF_BUILD").map_or(false, |e| e == "True") {
-            CiEnv::AzurePipelines
-        } else if env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
-            CiEnv::GitHubActions
-        } else {
-            CiEnv::None
-        }
-    }
-
-    pub fn is_ci() -> bool {
-        Self::current() != CiEnv::None
-    }
-
-    /// If in a CI environment, forces the command to run with colors.
-    pub fn force_coloring_in_ci(self, cmd: &mut Command) {
-        if self != CiEnv::None {
-            // Due to use of stamp/docker, the output stream of rustbuild is not
-            // a TTY in CI, so coloring is by-default turned off.
-            // The explicit `TERM=xterm` environment is needed for
-            // `--color always` to actually work. This env var was lost when
-            // compiling through the Makefile. Very strange.
-            cmd.env("TERM", "xterm").args(&["--color", "always"]);
-        }
-    }
-}
-
 pub fn forcing_clang_based_tests() -> bool {
     if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
         match &var.to_string_lossy().to_lowercase()[..] {
@@ -441,6 +412,23 @@ pub fn output(cmd: &mut Command) -> String {
     String::from_utf8(output.stdout).unwrap()
 }
 
+pub fn output_result(cmd: &mut Command) -> Result<String, String> {
+    let output = match cmd.stderr(Stdio::inherit()).output() {
+        Ok(status) => status,
+        Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)),
+    };
+    if !output.status.success() {
+        return Err(format!(
+            "command did not execute successfully: {:?}\n\
+             expected success, got: {}\n{}",
+            cmd,
+            output.status,
+            String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+        ));
+    }
+    Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?)
+}
+
 /// Returns the last-modified time for `path`, or zero if it doesn't exist.
 pub fn mtime(path: &Path) -> SystemTime {
     fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
index 93ef7dfcbf54906d2335e329f5e924e6db1fb699..0f5df95a0dd4bce79eb176e51646271f8fd25f14 100644 (file)
@@ -30,18 +30,18 @@ RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7
 RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
 
 ENV \
-    AR_x86_64_fuchsia=x86_64-fuchsia-ar \
-    CC_x86_64_fuchsia=x86_64-fuchsia-clang \
-    CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
-    CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \
-    CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
-    LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \
-    AR_aarch64_fuchsia=aarch64-fuchsia-ar \
-    CC_aarch64_fuchsia=aarch64-fuchsia-clang \
-    CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
-    CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \
-    CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
-    LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \
+    AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
+    CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
+    CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+    CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
+    CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+    LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \
+    AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
+    CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
+    CFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+    CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \
+    CXXFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+    LDFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \
     AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
     CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
     CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
@@ -99,19 +99,19 @@ RUN /tmp/freebsd-toolchain.sh i686
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar
-ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \
+ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar
+ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \
 -C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \
 -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \
 -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib
-ENV CARGO_TARGET_AARCH64_FUCHSIA_AR /usr/local/bin/llvm-ar
-ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
+ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar
+ENV CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS \
 -C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \
 -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot/lib \
 -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib
 
-ENV TARGETS=x86_64-fuchsia
-ENV TARGETS=$TARGETS,aarch64-fuchsia
+ENV TARGETS=x86_64-unknown-fuchsia
+ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
 ENV TARGETS=$TARGETS,wasm32-unknown-unknown
 ENV TARGETS=$TARGETS,wasm32-wasi
 ENV TARGETS=$TARGETS,sparcv9-sun-solaris
index 80db925775424c0e052669c9fbc0cf2757a35278..d762b4672c62ec0e49b8ecbd23cc378cc37a8ffd 100755 (executable)
@@ -29,9 +29,9 @@ install_clang() {
   # CFLAGS and CXXFLAGS env variables in main Dockerfile handle sysroot linking
   for arch in x86_64 aarch64; do
     for tool in clang clang++; do
-      ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-fuchsia-${tool}
+      ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-unknown-fuchsia-${tool}
     done
-    ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar
+    ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-unknown-fuchsia-ar
   done
 
   popd > /dev/null
index 78fee152eb9d4c198b33fecf3cbb0353f01af2b9..dc0e591cad6f6f9aec51a1ab2eec129f01e9988b 100644 (file)
@@ -32,5 +32,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
-ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
-ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy
+ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
index 475434e5aef8639abff9ae9cae4b20c84c0df7f6..c39e9c5fbc9d6e0e02eeb4fe453d25ea3e11ff21 100644 (file)
@@ -1 +1 @@
-0.13.4
\ No newline at end of file
+0.14.1
\ No newline at end of file
index 3e86339859dd360528d5ff6719286f58ae407a8d..c8d1ff9aefb7e49c96b5c151edb1f351afa88193 100755 (executable)
@@ -4,7 +4,7 @@
 The Rust toolchain test runner for Fuchsia.
 
 For instructions on running the compiler test suite, see
-https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-fuchsia-and-x86_64-fuchsia
+https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-unknown-fuchsia-and-x86_64-unknown-fuchsia
 """
 
 import argparse
@@ -110,9 +110,9 @@ class TestEnvironment:
 
     def rustlib_dir(self):
         if self.target_arch == "x64":
-            return "x86_64-fuchsia"
+            return "x86_64-unknown-fuchsia"
         if self.target_arch == "arm64":
-            return "aarch64-fuchsia"
+            return "aarch64-unknown-fuchsia"
         raise Exception(f"Unrecognized target architecture {self.target_arch}")
 
     def libs_dir(self):
index f05bb81d4a1e3b31ba260b357e237911979d8f17..0db9c993eecb407f2fd72cb4a3a0a76ef3535cb4 100755 (executable)
@@ -45,14 +45,6 @@ fi
 ci_dir=`cd $(dirname $0) && pwd`
 source "$ci_dir/shared.sh"
 
-if command -v python > /dev/null; then
-    PYTHON="python"
-elif command -v python3 > /dev/null; then
-    PYTHON="python3"
-else
-    PYTHON="python2"
-fi
-
 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"
@@ -192,16 +184,16 @@ if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
   $SRC/configure --set rust.parallel-compiler
 
   # Save the build metrics before we wipe the directory
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mv build/metrics.json .
   fi
   rm -rf build
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mkdir build
     mv metrics.json build
   fi
 
-  CARGO_INCREMENTAL=0 $PYTHON ../x.py check
+  CARGO_INCREMENTAL=0 ../x check
 fi
 
 sccache --show-stats || true
index a60f4316ec923a5ac2ed6a2eba6960edb832d855..2bd5d42c9956369132228da6409f0e68da56c51a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855
+Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
index dd37e21ccee43918ed18a71581bb2af537ffe4fc..8ca261268068d80c0969260fff15199bad87b587 160000 (submodule)
@@ -1 +1 @@
-Subproject commit dd37e21ccee43918ed18a71581bb2af537ffe4fc
+Subproject commit 8ca261268068d80c0969260fff15199bad87b587
index 995df09b65c582eb6290ab7ea5d9485983eb4c37..8888f9428fe9a48f31de6bd2cef9b9bf80791edc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 995df09b65c582eb6290ab7ea5d9485983eb4c37
+Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
index 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3..b3e2a6e6c8a3aae5b5d950c63046f23bae07096d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3
+Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d
index 2d3b830946145825c91580157c78e7de62c3fa95..752f1cc4aba0304675f7b0e4bb49a1df67c069f7 100644 (file)
     - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
     - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
+    - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [\*-android and \*-androideabi](platform-support/android.md)
-    - [\*-fuchsia](platform-support/fuchsia.md)
+    - [\*-unknown-fuchsia](platform-support/fuchsia.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
     - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
index d0c3ddf2606245fb5acdc000e1e7de126dc881f8..7ff26e420f1b3bdaec0684f812babc2d978e84cf 100644 (file)
@@ -124,7 +124,7 @@ target | std | notes
 -------|:---:|-------
 `aarch64-apple-ios` | ✓ | ARM64 iOS
 [`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64
-`aarch64-fuchsia` | ✓ | ARM64 Fuchsia
+`aarch64-unknown-fuchsia` | ✓ | ARM64 Fuchsia
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
 `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
 `aarch64-unknown-none` | * | Bare ARM64, hardfloat
@@ -177,7 +177,7 @@ target | std | notes
 `wasm32-wasi` | ✓ | WebAssembly with WASI
 `x86_64-apple-ios` | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
-`x86_64-fuchsia` | ✓ | 64-bit Fuchsia
+`x86_64-unknown-fuchsia` | ✓ | 64-bit Fuchsia
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
 `x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
 `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
@@ -235,6 +235,7 @@ target | std | host | notes
 `armv6-unknown-netbsd-eabihf` | ? |  |
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
+[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? |  | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
diff --git a/src/doc/rustc/src/platform-support/armv7-sony-vita-eabihf.md b/src/doc/rustc/src/platform-support/armv7-sony-vita-eabihf.md
new file mode 100644 (file)
index 0000000..6619c90
--- /dev/null
@@ -0,0 +1,127 @@
+# armv7-sony-vita-eabihf
+
+**Tier: 3**
+
+This tier supports the ARM Cortex A9 processor running on a PlayStation Vita console. `armv7-vita-newlibeabihf` aims to have support for `std` crate using `newlib` as a bridge.
+
+## Designated Developers
+
+* [@amg98](https://github.com/amg98)
+
+## Requirements
+
+This target is cross compiled, and requires installing [VITASDK](https://vitasdk.org/) toolchain on your system.
+
+## Building
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`:
+
+```toml
+[build]
+build-stage = 1
+target = ["armv7-sony-vita-newlibeabihf"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+## Building and Running Rust Programs
+
+To test your developed rust programs for PlayStation Vita, first you have to prepare a proper executable for the device using the resulting ELF file you get from compilation step. The needed steps can be automated using tools like `cargo-make`. Use the example below as a template for your project:
+
+```toml
+[env]
+TITLE = "Rust Hello World"
+TITLEID = "RUST00001"
+# At least a "sce_sys" folder should be place there for app metadata (title, icons, description...)
+# You can find sample assets for that on $VITASDK/share/gcc-arm-vita-eabi/samples/hello_world/sce_sys/
+STATIC_DIR = "static"   # Folder where static assets should be placed (sce_sys folder is at $STATIC_DIR/sce_sys)
+CARGO_TARGET_DIR = { script = ["echo ${CARGO_TARGET_DIR:=target}"] }
+RUST_TARGET_PATH = { script = ["echo $(pwd)"]}
+RUST_TARGET = "armv7-sony-vita-newlibeabihf"
+CARGO_OUT_DIR = "${CARGO_TARGET_DIR}/${RUST_TARGET}/release"
+
+[tasks.xbuild]
+# This is the command where you get the ELF executable file (e.g. call to cargo build)
+
+[tasks.strip]
+description = "Strip the produced ELF executable."
+dependencies = ["xbuild"]
+command = "arm-vita-eabi-strip"
+args = ["-g", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_FS_NAME}.elf']
+
+[tasks.velf]
+description = "Build an VELF executable from the obtained ELF file."
+dependencies = ["strip"]
+command = "vita-elf-create"
+args = ['${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.elf', '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf']
+
+[tasks.eboot-bin]
+description = "Build an `eboot.bin` file from the obtained VELF file."
+dependencies = ["velf"]
+command = "vita-make-fself"
+args = ["-s", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf', '${CARGO_OUT_DIR}/eboot.bin']
+
+[tasks.param-sfo]
+description = "Build the `param.sfo` manifest using with given TITLE and TITLEID."
+command = "vita-mksfoex"
+args = ["-s", 'TITLE_ID=${TITLEID}', '${TITLE}', '${CARGO_OUT_DIR}/param.sfo']
+
+[tasks.manifest]
+description = "List all static resources into a manifest file."
+script = [
+  'mkdir -p "${CARGO_OUT_DIR}"',
+  '''
+  if [ -d "${STATIC_DIR}" ]; then
+    find "${STATIC_DIR}" -type f > "${CARGO_OUT_DIR}/MANIFEST"
+  else
+    touch "${CARGO_OUT_DIR}/MANIFEST"
+  fi
+  '''
+]
+
+[tasks.vpk]
+description = "Build a VPK distribution of the project executable and resources."
+dependencies = ["eboot-bin", "param-sfo", "manifest"]
+script_runner = "@rust"
+script = [
+    '''
+    use std::io::BufRead;
+    use std::fs::File;
+
+    fn main() {
+
+      let crate_name = env!("CARGO_MAKE_CRATE_NAME");
+      let static_dir = env!("STATIC_DIR");
+      let out_dir = std::path::PathBuf::from(env!("CARGO_OUT_DIR"));
+
+      let mut cmd = ::std::process::Command::new("vita-pack-vpk");
+      cmd.arg("-s").arg(out_dir.join("param.sfo"));
+      cmd.arg("-b").arg(out_dir.join("eboot.bin"));
+
+      // Add files from MANIFEST
+      if let Ok(file) = File::open(out_dir.join("MANIFEST")) {
+          let mut reader = ::std::io::BufReader::new(file);
+          let mut lines = reader.lines();
+          while let Some(Ok(line)) = lines.next() {
+              let p1 = ::std::path::PathBuf::from(line);            // path on FS
+              let p2 = p1.strip_prefix(static_dir).unwrap();        // path in VPK
+              cmd.arg("--add").arg(format!("{}={}", p1.display(), p2.display()));
+          }
+      }
+
+      cmd.arg(out_dir.join(format!("{}.vpk", crate_name)))
+        .output()
+        .expect("command failed.");
+    }
+    '''
+]
+```
+
+After running the above script, you should be able to get a *.vpk file in the same folder your *.elf executable resides. Now you can pick it and install it on your own PlayStation Vita using, for example, [VitaShell](https://github.com/TheOfficialFloW/VitaShell/releases) or you can use an emulator. For the time being, the most mature emulator for PlayStation Vita is [Vita3K](https://vita3k.org/), although I personally recommend testing your programs in real hardware, as the emulator is quite experimental.
index cc4ee2e67b14eb7610c7bd9e6b4bbf140c334bb5..95c242cc161e9a388525c8a5a281e8c78d1559b1 100644 (file)
@@ -1,4 +1,4 @@
-# `aarch64-fuchsia` and `x86_64-fuchsia`
+# `aarch64-unknown-fuchsia` and `x86_64-unknown-fuchsia`
 
 **Tier: 2**
 
@@ -67,7 +67,7 @@ This walkthrough will cover:
 1. Building a Fuchsia package.
 1. Publishing and running a Fuchsia package to a Fuchsia emulator.
 
-For the purposes of this walkthrough, we will only target `x86_64-fuchsia`.
+For the purposes of this walkthrough, we will only target `x86_64-unknown-fuchsia`.
 
 ## Compiling a Rust binary targeting Fuchsia
 
@@ -83,8 +83,8 @@ to handle the installation of Fuchsia targets for you. This can be done by issui
 the following commands:
 
 ```sh
-rustup target add x86_64-fuchsia
-rustup target add aarch64-fuchsia
+rustup target add x86_64-unknown-fuchsia
+rustup target add aarch64-unknown-fuchsia
 ```
 
 After installing our Fuchsia targets, we can now compile a Rust binary that targets
@@ -127,7 +127,7 @@ during compilation:
 
 **`.cargo/config.toml`**
 ```txt
-[target.x86_64-fuchsia]
+[target.x86_64-unknown-fuchsia]
 
 rustflags = [
     "-Lnative=<SDK_PATH>/arch/x64/lib",
@@ -159,10 +159,10 @@ hello_fuchsia/
 Finally, we can build our rust binary as:
 
 ```sh
-cargo build --target x86_64-fuchsia
+cargo build --target x86_64-unknown-fuchsia
 ```
 
-Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`,
+Now we have a Rust binary at `target/x86_64-unknown-fuchsia/debug/hello_fuchsia`,
 targeting our desired Fuchsia target.
 
 **Current directory structure**
@@ -171,7 +171,7 @@ hello_fuchsia/
 ┣━ src/
 ┃  ┗━ main.rs
 ┣━ target/
-┃  ┗━ x86_64-fuchsia/
+┃  ┗━ x86_64-unknown-fuchsia/
 ┃     ┗━ debug/
 ┃        ┗━ hello_fuchsia
 ┣━ Cargo.toml
@@ -193,16 +193,19 @@ configuration in `config.toml`:
 
 ```toml
 [build]
-target = ["<host_platform>", "aarch64-fuchsia", "x86_64-fuchsia"]
+target = ["<host_platform>", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia"]
 
 [rust]
 lld = true
 
-[target.x86_64-fuchsia]
+[llvm]
+download-ci-llvm = false
+
+[target.x86_64-unknown-fuchsia]
 cc = "clang"
 cxx = "clang++"
 
-[target.aarch64-fuchsia]
+[target.aarch64-unknown-fuchsia]
 cc = "clang"
 cxx = "clang++"
 ```
@@ -233,14 +236,14 @@ a script we name `config-env.sh`:
 # Configure this environment variable to be the path to the downloaded SDK
 export SDK_PATH="<SDK path goes here>"
 
-export CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
-export CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/arm64/sysroot -Lnative=${SDK_PATH}/arch/arm64/sysroot/lib -Lnative=${SDK_PATH}/arch/arm64/lib"
-export CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
-export LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
-export CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib"
+export CFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export CXXFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export LDFLAGS_aarch64_unknown_fuchsia="--target=aarch64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/arm64/sysroot -L${SDK_PATH}/arch/arm64/lib"
+export CARGO_TARGET_AARCH64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/arm64/sysroot -Lnative=${SDK_PATH}/arch/arm64/sysroot/lib -Lnative=${SDK_PATH}/arch/arm64/lib"
+export CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include"
+export LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib"
+export CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib"
 ```
 
 Finally, the Rust compiler can be built and installed:
@@ -285,7 +288,7 @@ hello_fuchsia/
 Using your freshly installed `rustc`, you can compile a binary for Fuchsia using
 the following options:
 
-* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia
+* `--target x86_64-unknown-fuchsia`/`--target aarch64-unknown-fuchsia`: Targets the Fuchsia
   platform of your choice
 * `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
   the SDK
@@ -296,7 +299,7 @@ Putting it all together:
 
 ```sh
 # Configure these for the Fuchsia target of your choice
-TARGET_ARCH="<x86_64-fuchsia|aarch64-fuchsia>"
+TARGET_ARCH="<x86_64-unknown-fuchsia|aarch64-unknown-fuchsia>"
 ARCH="<x64|aarch64>"
 
 rustc \
@@ -322,16 +325,16 @@ Before moving on, double check your directory structure:
 **Current directory structure**
 ```txt
 hello_fuchsia/
-┣━ src/                     (if using rustc)
-┃   ┗━ hello_fuchsia.rs     ...
-┣━ bin/                     ...
-┃  ┗━ hello_fuchsia         ...
-┣━ src/                     (if using cargo)
-┃  ┗━ main.rs               ...
-┗━ target/                  ...
-   ┗━ x86_64-fuchsia/       ...
-      ┗━ debug/             ...
-         ┗━ hello_fuchsia   ...
+┣━ src/                         (if using rustc)
+┃   ┗━ hello_fuchsia.rs         ...
+┣━ bin/                         ...
+┃  ┗━ hello_fuchsia             ...
+┣━ src/                         (if using cargo)
+┃  ┗━ main.rs                   ...
+┗━ target/                      ...
+   ┗━ x86_64-unknown-fuchsia/   ...
+      ┗━ debug/                 ...
+         ┗━ hello_fuchsia       ...
 ```
 
 With our Rust binary built, we can move to creating a Fuchsia package.
@@ -368,7 +371,7 @@ package must contain one.
 
 **`pkg/hello_fuchsia.manifest` if using cargo**
 ```txt
-bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia
+bin/hello_fuchsia=target/x86_64-unknown-fuchsia/debug/hello_fuchsia
 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
 meta/package=pkg/meta/package
@@ -543,16 +546,16 @@ structure will look like:
 **Final directory structure**
 ```txt
 hello_fuchsia/
-┣━ src/                     (if using rustc)
-┃   ┗━ hello_fuchsia.rs     ...
-┣━ bin/                     ...
-┃  ┗━ hello_fuchsia         ...
-┣━ src/                     (if using cargo)
-┃  ┗━ main.rs               ...
-┣━ target/                  ...
-┃  ┗━ x86_64-fuchsia/       ...
-┃     ┗━ debug/             ...
-┃        ┗━ hello_fuchsia   ...
+┣━ src/                         (if using rustc)
+┃   ┗━ hello_fuchsia.rs         ...
+┣━ bin/                         ...
+┃  ┗━ hello_fuchsia             ...
+┣━ src/                         (if using cargo)
+┃  ┗━ main.rs                   ...
+┣━ target/                      ...
+┃  ┗━ x86_64-unknown-fuchsia/   ...
+┃     ┗━ debug/                 ...
+┃        ┗━ hello_fuchsia       ...
 ┗━ pkg/
    ┣━ meta/
    ┃  ┣━ package
@@ -641,8 +644,8 @@ Tests can be run in the same way as a regular binary.
 
 * If using `cargo`, you can simply pass `test --no-run`
 to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example,
-this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable
-binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
+this would look like `cargo test --target x86_64-unknown-fuchsia --no-run`, and moving the executable
+binary path found from the line `Executable unittests src/main.rs (target/x86_64-unknown-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
 into `pkg/hello_fuchsia.manifest`.
 
 * If using the compiled `rustc`, you can simply pass `--test`
@@ -711,7 +714,7 @@ run the full `src/test/ui` test suite:
     --config config.toml                                                      \
     --stage=2                                                                 \
     test src/test/ui                                                          \
-    --target x86_64-fuchsia                                                   \
+    --target x86_64-unknown-fuchsia                                           \
     --run=always --jobs 1                                                     \
     --test-args --target-rustcflags                                           \
     --test-args -L                                                            \
@@ -755,7 +758,7 @@ directory to launch `zxdb`:
 **In separate terminal**
 ```sh
 ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
-    --symbol-path target/x86_64-fuchsia/debug
+    --symbol-path target/x86_64-unknown-fuchsia/debug
 ```
 
 * `--symbol-path` gets required symbol paths, which are
@@ -851,7 +854,7 @@ source code:
 
 ```sh
 ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
-    --symbol-path target/x86_64-fuchsia/debug \
+    --symbol-path target/x86_64-unknown-fuchsia/debug \
     --build-dir ${RUST_SRC_PATH}/rust \
     --build-dir ${FUCHSIA_SRC_PATH}/fuchsia/out/default
 ```
index 5859df83f645bc8ea5e3cc4fd4e6057a29fad440..f291cde2e5a0dbb45195804334ea76c2d8a26bea 100644 (file)
@@ -1,7 +1,10 @@
 # Targets
 
 `rustc` is a cross-compiler by default. This means that you can use any compiler to build for any
-architecture. The list of *targets* are the possible architectures that you can build for.
+architecture. The list of *targets* are the possible architectures that you can build for. See
+the [Platform Support](../platform-support.md) page for a detailed list of targets, or
+[Built-in Targets](built-in.md) for instructions on how to view what is available for your version
+of `rustc`.
 
 To see all the options that you can set with a target, see the docs
 [here](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.Target.html).
index e3b08648999804da3d1bf78ef7373b36f14b2ac2..8ecf05f0e121f7316fc9301b59f5227239f0436a 100644 (file)
@@ -9,11 +9,11 @@ are the same:
 
 ```rust,no_run
 /// This is a doc comment.
-#[doc = " This is a doc comment."]
+#[doc = r" This is a doc comment."]
 # fn f() {}
 ```
 
-(Note the leading space in the attribute version.)
+(Note the leading space and the raw string literal in the attribute version.)
 
 In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is
 when generating documentation in macros; the `collapse-docs` pass will combine multiple
diff --git a/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md b/src/doc/unstable-book/src/compiler-flags/dump-mono-stats-format.md
new file mode 100644 (file)
index 0000000..a497a75
--- /dev/null
@@ -0,0 +1,6 @@
+# `dump-mono-stats-format`
+
+--------------------
+
+The `-Z dump-mono-stats-format` compiler flag controls what file format to use for `-Z dump-mono-stats`.
+The default is markdown; currently JSON is also supported. JSON can be useful for programatically manipulating the results (e.g. to find the item that took the longest to compile).
diff --git a/src/doc/unstable-book/src/compiler-flags/dump-mono-stats.md b/src/doc/unstable-book/src/compiler-flags/dump-mono-stats.md
new file mode 100644 (file)
index 0000000..4c8bc8b
--- /dev/null
@@ -0,0 +1,14 @@
+# `dump-mono-stats`
+
+--------------------
+
+The `-Z dump-mono-stats` compiler flag generates a file with a list of the monomorphized items in the current crate.
+It is useful for investigating compile times.
+
+It accepts an optional directory where the file will be located. If no directory is specified, the file will be placed in the current directory.
+
+See also `-Z dump-mono-stats-format` and `-Z print-mono-items`. Unlike `print-mono-items`,
+`dump-mono-stats` aggregates monomorphized items by definition and includes a size estimate of how
+large the item is when codegened.
+
+See <https://rustc-dev-guide.rust-lang.org/backend/monomorph.html> for an overview of monomorphized items.
index a9616c34bffcb6be02e464c0b8f915c1b7cc1319..70c3a445b864f17e825141ec5a1ecebec5f794b2 100644 (file)
@@ -50,10 +50,10 @@ with runtime flag `ASAN_OPTIONS=detect_leaks=1` on macOS.
 AddressSanitizer is supported on the following targets:
 
 * `aarch64-apple-darwin`
-* `aarch64-fuchsia`
+* `aarch64-unknown-fuchsia`
 * `aarch64-unknown-linux-gnu`
 * `x86_64-apple-darwin`
-* `x86_64-fuchsia`
+* `x86_64-unknown-fuchsia`
 * `x86_64-unknown-freebsd`
 * `x86_64-unknown-linux-gnu`
 
index 2a3086338b4bfe0591961272c2ac9582213ae574..7a846d44ad6a8e9484b51aaf41705683feef5742 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 #
-# Call `tidy --bless` before git push
+# Call `tidy` before git push
 # Copy this script to .git/hooks to activate,
 # and remove it from .git/hooks to deactivate.
 #
index 92886bbfe26b4e5d03953f9eb3362bfe03bd3ae9..025a4379f45a31a289177d6daad62200c3aa6302 100644 (file)
@@ -1612,7 +1612,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
     match ty.kind {
         TyKind::Never => Primitive(PrimitiveType::Never),
         TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
-        TyKind::Rptr(ref l, ref m) => {
+        TyKind::Ref(ref l, ref m) => {
             let lifetime = if l.is_anonymous() { None } else { Some(clean_lifetime(*l, cx)) };
             BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
         }
@@ -1853,7 +1853,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
         ty::Infer(..) => panic!("Infer"),
-        ty::Error(_) => panic!("Error"),
+        ty::Error(_) => rustc_errors::FatalError.raise(),
     }
 }
 
@@ -1949,20 +1949,27 @@ pub(crate) fn clean_field_with_def_id(
 }
 
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
+    let discriminant = match variant.discr {
+        ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+        ty::VariantDiscr::Relative(_) => None,
+    };
+
     let kind = match variant.ctor_kind() {
-        Some(CtorKind::Const) => Variant::CLike(match variant.discr {
-            ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
-            ty::VariantDiscr::Relative(_) => None,
-        }),
-        Some(CtorKind::Fn) => Variant::Tuple(
+        Some(CtorKind::Const) => VariantKind::CLike,
+        Some(CtorKind::Fn) => VariantKind::Tuple(
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
-        None => Variant::Struct(VariantStruct {
-            ctor_kind: None,
+        None => VariantKind::Struct(VariantStruct {
             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         }),
     };
-    Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
+
+    Item::from_def_id_and_parts(
+        variant.def_id,
+        Some(variant.name),
+        VariantItem(Variant { kind, discriminant }),
+        cx,
+    )
 }
 
 fn clean_variant_data<'tcx>(
@@ -1970,19 +1977,22 @@ fn clean_variant_data<'tcx>(
     disr_expr: &Option<hir::AnonConst>,
     cx: &mut DocContext<'tcx>,
 ) -> Variant {
-    match variant {
-        hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
-            ctor_kind: None,
+    let discriminant = disr_expr.map(|disr| Discriminant {
+        expr: Some(disr.body),
+        value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+    });
+
+    let kind = match variant {
+        hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
         }),
         hir::VariantData::Tuple(..) => {
-            Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
+            VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
         }
-        hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
-            expr: Some(disr.body),
-            value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
-        })),
-    }
+        hir::VariantData::Unit(..) => VariantKind::CLike,
+    };
+
+    Variant { discriminant, kind }
 }
 
 fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
index 7a13e7e36d169c3c50cb31561469381a9414b651..827afafbba3b62ca6c2833b5b4b66119c3d9879d 100644 (file)
@@ -807,8 +807,11 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
         match self {
             StructItem(s) => s.fields.iter(),
             UnionItem(u) => u.fields.iter(),
-            VariantItem(Variant::Struct(v)) => v.fields.iter(),
-            VariantItem(Variant::Tuple(v)) => v.iter(),
+            VariantItem(v) => match &v.kind {
+                VariantKind::CLike => [].iter(),
+                VariantKind::Tuple(t) => t.iter(),
+                VariantKind::Struct(s) => s.fields.iter(),
+            },
             EnumItem(e) => e.variants.iter(),
             TraitItem(t) => t.items.iter(),
             ImplItem(i) => i.items.iter(),
@@ -824,7 +827,6 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | VariantItem(_)
             | ForeignFunctionItem(_)
             | ForeignStaticItem(_)
             | ForeignTypeItem
@@ -1740,7 +1742,7 @@ pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
     fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
         let t: PrimitiveType = match *self {
             Type::Path { ref path } => return Some(path.def_id()),
-            DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
+            DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()),
             Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
             BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
@@ -2109,7 +2111,6 @@ pub(crate) fn has_stripped_entries(&self) -> bool {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 pub(crate) struct VariantStruct {
-    pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) fields: Vec<Item>,
 }
 
@@ -2136,17 +2137,23 @@ pub(crate) fn variants(&self) -> impl Iterator<Item = &Item> {
 }
 
 #[derive(Clone, Debug)]
-pub(crate) enum Variant {
-    CLike(Option<Discriminant>),
+pub(crate) struct Variant {
+    pub kind: VariantKind,
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum VariantKind {
+    CLike,
     Tuple(Vec<Item>),
     Struct(VariantStruct),
 }
 
 impl Variant {
     pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
-        match *self {
-            Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
-            Self::CLike(..) | Self::Tuple(_) => None,
+        match &self.kind {
+            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
+            VariantKind::CLike | VariantKind::Tuple(_) => None,
         }
     }
 }
@@ -2487,6 +2494,17 @@ pub(crate) fn new_simple(
     pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
         Self { kind: ImportKind::Glob, source, should_be_displayed }
     }
+
+    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
+        match self.source.did {
+            Some(did) => tcx
+                .get_attrs(did, sym::doc)
+                .filter_map(ast::Attribute::meta_item_list)
+                .flatten()
+                .has_word(sym::hidden),
+            None => false,
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
index c6f1f9de51a49a4745516e4f7a31cf59b8c1543a..656aeefb01a4a807ea8aa8b418957544a28c356c 100644 (file)
@@ -37,17 +37,21 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
                 i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 ImplItem(i)
             }
-            VariantItem(i) => match i {
-                Variant::Struct(mut j) => {
-                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Struct(j))
-                }
-                Variant::Tuple(fields) => {
-                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Tuple(fields))
-                }
-                Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
-            },
+            VariantItem(Variant { kind, discriminant }) => {
+                let kind = match kind {
+                    VariantKind::Struct(mut j) => {
+                        j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Struct(j)
+                    }
+                    VariantKind::Tuple(fields) => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Tuple(fields)
+                    }
+                    VariantKind::CLike => VariantKind::CLike,
+                };
+
+                VariantItem(Variant { kind, discriminant })
+            }
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
index d4d3e4f6ea7952c0399ca2c3e5066d361b222e64..c8899ee62b5f9c7456c96eacc3eaa44600c5a6e8 100644 (file)
@@ -309,7 +309,7 @@ pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
 
     pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
         let mut root = self.root_path();
-        let mut path = String::new();
+        let mut path: String;
         let cnum = span.cnum(self.sess());
 
         // We can safely ignore synthetic `SourceFile`s.
@@ -340,10 +340,24 @@ pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Opti
                 ExternalLocation::Unknown => return None,
             };
 
-            sources::clean_path(&src_root, file, false, |component| {
-                path.push_str(&component.to_string_lossy());
+            let href = RefCell::new(PathBuf::new());
+            sources::clean_path(
+                &src_root,
+                file,
+                |component| {
+                    href.borrow_mut().push(component);
+                },
+                || {
+                    href.borrow_mut().pop();
+                },
+            );
+
+            path = href.into_inner().to_string_lossy().to_string();
+
+            if let Some(c) = path.as_bytes().last() && *c != b'/' {
                 path.push('/');
-            });
+            }
+
             let mut fname = file.file_name().expect("source has no filename").to_os_string();
             fname.push(".html");
             path.push_str(&fname.to_string_lossy());
index a7b57c373e3bec3b4a9219758d8d020f2b1a0642..c16d6477fc37978c736e7c7ddf296be56f98311e 100644 (file)
@@ -1220,25 +1220,16 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                     w.write_str("    ");
                     let name = v.name.unwrap();
                     match *v.kind {
-                        clean::VariantItem(ref var) => match var {
-                            // FIXME(#101337): Show discriminant
-                            clean::Variant::CLike(..) => write!(w, "{}", name),
-                            clean::Variant::Tuple(ref s) => {
+                        // FIXME(#101337): Show discriminant
+                        clean::VariantItem(ref var) => match var.kind {
+                            clean::VariantKind::CLike => write!(w, "{}", name),
+                            clean::VariantKind::Tuple(ref s) => {
                                 write!(w, "{}(", name);
                                 print_tuple_struct_fields(w, cx, s);
                                 w.write_str(")");
                             }
-                            clean::Variant::Struct(ref s) => {
-                                render_struct(
-                                    w,
-                                    v,
-                                    None,
-                                    s.ctor_kind,
-                                    &s.fields,
-                                    "    ",
-                                    false,
-                                    cx,
-                                );
+                            clean::VariantKind::Struct(ref s) => {
+                                render_struct(w, v, None, None, &s.fields, "    ", false, cx);
                             }
                         },
                         _ => unreachable!(),
@@ -1286,25 +1277,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                 " rightside",
             );
             write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
-            if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+            let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+            if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
                 w.write_str("(");
                 print_tuple_struct_fields(w, cx, s);
                 w.write_str(")");
             }
             w.write_str("</h3></section>");
 
-            use crate::clean::Variant;
-
-            let heading_and_fields = match &*variant.kind {
-                clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
-                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
-                // the section if at least one field is documented.
-                clean::VariantItem(Variant::Tuple(fields))
-                    if fields.iter().any(|f| f.doc_value().is_some()) =>
-                {
-                    Some(("Tuple Fields", fields))
+            let heading_and_fields = match &variant_data.kind {
+                clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+                clean::VariantKind::Tuple(fields) => {
+                    // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                    // the section if at least one field is documented.
+                    if fields.iter().any(|f| f.doc_value().is_some()) {
+                        Some(("Tuple Fields", fields))
+                    } else {
+                        None
+                    }
                 }
-                _ => None,
+                clean::VariantKind::CLike => None,
             };
 
             if let Some((heading, fields)) = heading_and_fields {
index 8eb9c07f8a7964d9440383c8519052fa6372c20a..2d61519d6c9081bb7401cca103ab9a17fd7973aa 100644 (file)
@@ -322,8 +322,7 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
     match *clean_type {
         clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
         clean::DynTrait(ref bounds, _) => {
-            let path = &bounds[0].trait_;
-            Some(RenderTypeId::DefId(path.def_id()))
+            bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id()))
         }
         clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
         clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
index eaf149a43005b63fa249a10be15df1e54db3aec8..3ea4c4bea8828fbc4fbfdb8738b76b6501d9726a 100644 (file)
@@ -1,8 +1,9 @@
+use std::cell::RefCell;
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
 use std::path::{Component, Path};
-use std::rc::Rc;
+use std::rc::{Rc, Weak};
 
 use itertools::Itertools;
 use rustc_data_structures::flock;
@@ -184,23 +185,26 @@ fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String
 
     use std::ffi::OsString;
 
-    #[derive(Debug)]
+    #[derive(Debug, Default)]
     struct Hierarchy {
+        parent: Weak<Self>,
         elem: OsString,
-        children: FxHashMap<OsString, Hierarchy>,
-        elems: FxHashSet<OsString>,
+        children: RefCell<FxHashMap<OsString, Rc<Self>>>,
+        elems: RefCell<FxHashSet<OsString>>,
     }
 
     impl Hierarchy {
-        fn new(elem: OsString) -> Hierarchy {
-            Hierarchy { elem, children: FxHashMap::default(), elems: FxHashSet::default() }
+        fn with_parent(elem: OsString, parent: &Rc<Self>) -> Self {
+            Self { elem, parent: Rc::downgrade(parent), ..Self::default() }
         }
 
         fn to_json_string(&self) -> String {
-            let mut subs: Vec<&Hierarchy> = self.children.values().collect();
+            let borrow = self.children.borrow();
+            let mut subs: Vec<_> = borrow.values().collect();
             subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem));
             let mut files = self
                 .elems
+                .borrow()
                 .iter()
                 .map(|s| format!("\"{}\"", s.to_str().expect("invalid osstring conversion")))
                 .collect::<Vec<_>>();
@@ -220,36 +224,52 @@ fn to_json_string(&self) -> String {
                 files = files
             )
         }
-    }
 
-    if cx.include_sources {
-        let mut hierarchy = Hierarchy::new(OsString::new());
-        for source in cx
-            .shared
-            .local_sources
-            .iter()
-            .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok())
-        {
-            let mut h = &mut hierarchy;
-            let mut elems = source
+        fn add_path(self: &Rc<Self>, path: &Path) {
+            let mut h = Rc::clone(&self);
+            let mut elems = path
                 .components()
                 .filter_map(|s| match s {
                     Component::Normal(s) => Some(s.to_owned()),
+                    Component::ParentDir => Some(OsString::from("..")),
                     _ => None,
                 })
                 .peekable();
             loop {
                 let cur_elem = elems.next().expect("empty file path");
+                if cur_elem == ".." {
+                    if let Some(parent) = h.parent.upgrade() {
+                        h = parent;
+                    }
+                    continue;
+                }
                 if elems.peek().is_none() {
-                    h.elems.insert(cur_elem);
+                    h.elems.borrow_mut().insert(cur_elem);
                     break;
                 } else {
-                    let e = cur_elem.clone();
-                    h = h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e));
+                    let entry = Rc::clone(
+                        h.children
+                            .borrow_mut()
+                            .entry(cur_elem.clone())
+                            .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))),
+                    );
+                    h = entry;
                 }
             }
         }
+    }
 
+    if cx.include_sources {
+        let hierarchy = Rc::new(Hierarchy::default());
+        for source in cx
+            .shared
+            .local_sources
+            .iter()
+            .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok())
+        {
+            hierarchy.add_path(source);
+        }
+        let hierarchy = Rc::try_unwrap(hierarchy).unwrap();
         let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
         let make_sources = || {
             let (mut all_sources, _krates) =
index e639fadeb96733ddb5848e6ef9c677614eaaa5b0..799c497d13709a00d95c7fcf6a07dc2fc482f8c4 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_session::Session;
 use rustc_span::source_map::FileName;
 
+use std::cell::RefCell;
 use std::ffi::OsStr;
 use std::fs;
 use std::path::{Component, Path, PathBuf};
@@ -72,12 +73,22 @@ fn add_local_source(&mut self, item: &clean::Item) {
             return;
         }
 
-        let mut href = String::new();
-        clean_path(self.src_root, &p, false, |component| {
-            href.push_str(&component.to_string_lossy());
-            href.push('/');
-        });
+        let href = RefCell::new(PathBuf::new());
+        clean_path(
+            &self.src_root,
+            &p,
+            |component| {
+                href.borrow_mut().push(component);
+            },
+            || {
+                href.borrow_mut().pop();
+            },
+        );
 
+        let mut href = href.into_inner().to_string_lossy().to_string();
+        if let Some(c) = href.as_bytes().last() && *c != b'/' {
+            href.push('/');
+        }
         let mut src_fname = p.file_name().expect("source has no filename").to_os_string();
         src_fname.push(".html");
         href.push_str(&src_fname.to_string_lossy());
@@ -180,13 +191,28 @@ fn emit_source(
 
         let shared = Rc::clone(&self.cx.shared);
         // Create the intermediate directories
-        let mut cur = self.dst.clone();
-        let mut root_path = String::from("../../");
-        clean_path(&shared.src_root, &p, false, |component| {
-            cur.push(component);
-            root_path.push_str("../");
-        });
+        let cur = RefCell::new(PathBuf::new());
+        let root_path = RefCell::new(PathBuf::new());
+
+        clean_path(
+            &shared.src_root,
+            &p,
+            |component| {
+                cur.borrow_mut().push(component);
+                root_path.borrow_mut().push("..");
+            },
+            || {
+                cur.borrow_mut().pop();
+                root_path.borrow_mut().pop();
+            },
+        );
 
+        let root_path = PathBuf::from("../../").join(root_path.into_inner());
+        let mut root_path = root_path.to_string_lossy();
+        if let Some(c) = root_path.as_bytes().last() && *c != b'/' {
+            root_path += "/";
+        }
+        let mut cur = self.dst.join(cur.into_inner());
         shared.ensure_dir(&cur)?;
 
         let src_fname = p.file_name().expect("source has no filename").to_os_string();
@@ -232,11 +258,13 @@ fn emit_source(
 /// Takes a path to a source file and cleans the path to it. This canonicalizes
 /// things like ".." to components which preserve the "top down" hierarchy of a
 /// static HTML tree. Each component in the cleaned path will be passed as an
-/// argument to `f`. The very last component of the path (ie the file name) will
-/// be passed to `f` if `keep_filename` is true, and ignored otherwise.
-pub(crate) fn clean_path<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
+/// argument to `f`. The very last component of the path (ie the file name) is ignored.
+/// If a `..` is encountered, the `parent` closure will be called to allow the callee to
+/// handle it.
+pub(crate) fn clean_path<F, P>(src_root: &Path, p: &Path, mut f: F, mut parent: P)
 where
     F: FnMut(&OsStr),
+    P: FnMut(),
 {
     // make it relative, if possible
     let p = p.strip_prefix(src_root).unwrap_or(p);
@@ -244,12 +272,12 @@ pub(crate) fn clean_path<F>(src_root: &Path, p: &Path, keep_filename: bool, mut
     let mut iter = p.components().peekable();
 
     while let Some(c) = iter.next() {
-        if !keep_filename && iter.peek().is_none() {
+        if iter.peek().is_none() {
             break;
         }
 
         match c {
-            Component::ParentDir => f("up".as_ref()),
+            Component::ParentDir => parent(),
             Component::Normal(c) => f(c),
             _ => continue,
         }
index 1ba8d118b7644b36a32cd63cf00fdf31ba6a3017..77401e8b76e80ba3e2e05a014e0788981770bc41 100644 (file)
@@ -76,8 +76,6 @@
 }
 
 * {
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
        box-sizing: border-box;
 }
 
@@ -110,11 +108,7 @@ body {
        /* Then override it with `anywhere`, which is required to make non-Safari browsers break
           more aggressively when we want them to. */
        overflow-wrap: anywhere;
-
-       -webkit-font-feature-settings: "kern", "liga";
-       -moz-font-feature-settings: "kern", "liga";
        font-feature-settings: "kern", "liga";
-
        background-color: var(--main-background-color);
        color: var(--main-color);
 }
@@ -355,13 +349,10 @@ img {
        max-width: 100%;
 }
 
-.source .content {
-       overflow: visible;
-}
-
 .sub-logo-container, .logo-container {
        /* zero text boxes so that computed line height = image height exactly */
        line-height: 0;
+       display: block;
 }
 
 .sub-logo-container {
@@ -378,10 +369,6 @@ img {
        filter: var(--rust-logo-filter);
 }
 
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
-       background-color: var(--sidebar-background-color);
-}
-
 .sidebar {
        font-size: 0.875rem;
        flex: 0 0 200px;
@@ -400,7 +387,8 @@ img {
        overflow-y: hidden;
 }
 
-.source .sidebar, #src-sidebar-toggle, #source-sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle,
+#src-sidebar-toggle, #source-sidebar {
        background-color: var(--sidebar-background-color);
 }
 
@@ -508,7 +496,7 @@ ul.block, .block li {
        color: var(--sidebar-link-color);
 }
 .sidebar .current,
-.sidebar a:hover {
+.sidebar a:hover:not(.logo-container) {
        background-color: var(--sidebar-current-link-background-color);
 }
 
@@ -550,8 +538,6 @@ ul.block, .block li {
        overflow: initial;
        text-align: right;
        -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
        user-select: none;
        padding: 14px 8px;
        color: var(--src-line-numbers-span-color);
@@ -1109,7 +1095,6 @@ pre.rust .doccomment {
 }
 
 .example-wrap .tooltip:hover::after {
-       text-align: center;
        padding: 5px 3px 3px 3px;
        border-radius: 6px;
        margin-left: 5px;
@@ -1321,15 +1306,11 @@ a.test-arrow:hover {
        -webkit-appearance: none;
        opacity: 1;
 }
+
 #settings-menu, #help-button {
        margin-left: 4px;
        display: flex;
 }
-
-#settings-menu > a, #help-button > a, #copy-path {
-       width: 33px;
-}
-
 #settings-menu > a, #help-button > a {
        display: flex;
        align-items: center;
@@ -1341,6 +1322,7 @@ a.test-arrow:hover {
        /* Rare exception to specifying font sizes in rem. Since this is acting
           as an icon, it's okay to specify their sizes in pixels. */
        font-size: 20px;
+       width: 33px;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
@@ -1356,6 +1338,7 @@ a.test-arrow:hover {
        padding: 0;
        padding-left: 2px;
        border: 0;
+       width: 33px;
 }
 #copy-path > img {
        filter: var(--copy-path-img-filter);
@@ -1384,7 +1367,7 @@ kbd {
        vertical-align: middle;
        border: solid 1px var(--border-color);
        border-radius: 3px;
-       color: var(--kbd--color);
+       color: var(--kbd-color);
        background-color: var(--kbd-background);
        box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
 }
@@ -1397,31 +1380,10 @@ details.dir-entry {
        padding-left: 4px;
 }
 
-details.dir-entry > summary::after {
-       content: " ►";
-       position: absolute;
-       left: -15px;
-       top: 0px;
-       font-size: 80%;
-       padding: 2px 0px;
-       /* set width to cover gap between arrow and text */
-       width: 25px;
-}
-
-details[open].dir-entry > summary::after {
-       content: " ▼";
-}
-
-details.dir-entry > summary::-webkit-details-marker,
-details.dir-entry > summary::marker {
-       display: none;
-}
-
 details.dir-entry > summary {
-       margin: 0 0 0 13px;
-       list-style: none;
+       margin: 0 0 0 -4px;
+       padding: 0 0 0 4px;
        cursor: pointer;
-       position: relative;
 }
 
 details.dir-entry div.folders, details.dir-entry div.files {
@@ -1607,7 +1569,7 @@ in storage.js
 
        /* Hide the logo and item name from the sidebar. Those are displayed
           in the mobile-topbar instead. */
-       .sidebar .sidebar-logo,
+       .sidebar .logo-container,
        .sidebar .location {
                display: none;
        }
@@ -1636,14 +1598,10 @@ in storage.js
 
        .sidebar.shown,
        .source-sidebar-expanded .source .sidebar,
-       .sidebar:focus-within {
+       .rustdoc:not(.source) .sidebar:focus-within {
                left: 0;
        }
 
-       .rustdoc.source > .sidebar {
-               width: 0;
-       }
-
        .mobile-topbar h2 {
                padding-bottom: 0;
                margin: auto 0.5em auto auto;
@@ -1693,10 +1651,6 @@ in storage.js
                margin-top: 1em;
        }
 
-       .content {
-               margin-left: 0px;
-       }
-
        .anchor {
                display: none !important;
        }
@@ -1871,9 +1825,13 @@ in storage.js
        font-size: 12px;
        position: relative;
        bottom: 1px;
-       border-width: 1px;
-       border-style: solid;
+       border: 1px solid var(--scrape-example-help-border-color);
        border-radius: 50px;
+       color: var(--scrape-example-help-color);
+}
+.scraped-example-list .scrape-help:hover {
+       border-color: var(--scrape-example-help-hover-border-color);
+       color: var(--scrape-example-help-hover-color);
 }
 
 .scraped-example {
@@ -1959,6 +1917,13 @@ in storage.js
        overflow-x: hidden;
 }
 
+.scraped-example .example-wrap .rust span.highlight {
+       background: var(--scrape-example-code-line-highlight);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+       background: var(--scrape-example-code-line-highlight-focus);
+}
+
 .more-examples-toggle {
        max-width: calc(100% + 25px);
        margin-top: 10px;
index 4ffc25e2688e4d02bb3285cac4febe8edea19694..979e7e0f999eda96a2d18ab552c3b668076d8965 100644 (file)
@@ -91,6 +91,12 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --codeblock-link-background: #333;
        --scrape-example-toggle-line-background: #999;
        --scrape-example-toggle-line-hover-background: #c5c5c5;
+       --scrape-example-code-line-highlight: rgb(91, 59, 1);
+       --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
+       --scrape-example-help-border-color: #aaa;
+       --scrape-example-help-color: #eee;
+       --scrape-example-help-hover-border-color: #fff;
+       --scrape-example-help-hover-color: #fff;
 }
 
 h1, h2, h3, h4 {
@@ -162,18 +168,18 @@ pre, .rustdoc.source .example-wrap {
        color: #788797;
 }
 
-#titles > button.selected {
+#search-tabs > button.selected {
        background-color: #141920 !important;
        border-bottom: 1px solid #ffb44c !important;
        border-top: none;
 }
 
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
        background-color: transparent !important;
        border: none;
 }
 
-#titles > button:hover {
+#search-tabs > button:hover {
        border-bottom: 1px solid rgba(242, 151, 24, 0.3);
 }
 
@@ -183,11 +189,7 @@ individually rather than as a group) */
 /* FIXME: these rules should be at the bottom of the file but currently must be
 above the `@media (max-width: 700px)` rules due to a bug in the css checker */
 /* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-pre.rust .lifetime {}
-pre.rust .kw {}
-#titles > button:hover, #titles > button.selected {}
-pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {}
-pre.rust .kw-2, pre.rust .prelude-ty {}
+#search-tabs > button:hover, #search-tabs > button.selected {}
 
 #settings-menu > a img {
        filter: invert(100);
@@ -202,20 +204,6 @@ pre.rust .kw-2, pre.rust .prelude-ty {}
        color: #ffb44c;
 }
 
-.scraped-example-list .scrape-help {
-       border-color: #aaa;
-       color: #eee;
-}
-.scraped-example-list .scrape-help:hover {
-       border-color: white;
-       color: white;
-}
-.scraped-example .example-wrap .rust span.highlight {
-       background: rgb(91, 59, 1);
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
-       background: rgb(124, 75, 15);
-}
 .scraped-example:not(.expanded) .code-wrapper::before {
        background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
 }
index a7922cdeba1004b07f990843477c168bc8616c5a..fb15863b027ca5f992954da7656696bc8dec4fb3 100644 (file)
        --codeblock-link-background: #333;
        --scrape-example-toggle-line-background: #999;
        --scrape-example-toggle-line-hover-background: #c5c5c5;
+       --scrape-example-code-line-highlight: rgb(91, 59, 1);
+       --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
+       --scrape-example-help-border-color: #aaa;
+       --scrape-example-help-color: #eee;
+       --scrape-example-help-hover-border-color: #fff;
+       --scrape-example-help-hover-color: #fff;
 }
 
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
        background-color: #252525;
        border-top-color: #252525;
 }
 
-#titles > button:hover, #titles > button.selected {
+#search-tabs > button:hover, #search-tabs > button.selected {
        border-top-color: #0089ff;
        background-color: #353535;
 }
 
-.scraped-example-list .scrape-help {
-       border-color: #aaa;
-       color: #eee;
-}
-.scraped-example-list .scrape-help:hover {
-       border-color: white;
-       color: white;
-}
-.scraped-example .example-wrap .rust span.highlight {
-       background: rgb(91, 59, 1);
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
-       background: rgb(124, 75, 15);
-}
 .scraped-example:not(.expanded) .code-wrapper::before {
        background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
 }
index aff46f8dc6dff3b1afca88a04818c5fbe0c0cb62..053fa78d1dc5884dae832d7524e8c3654b3e0828 100644 (file)
        --codeblock-link-background: #eee;
        --scrape-example-toggle-line-background: #ccc;
        --scrape-example-toggle-line-hover-background: #999;
+       --scrape-example-code-line-highlight: #fcffd6;
+       --scrape-example-code-line-highlight-focus: #f6fdb0;
+       --scrape-example-help-border-color: #555;
+       --scrape-example-help-color: #333;
+       --scrape-example-help-hover-border-color: #000;
+       --scrape-example-help-hover-color: #000;
 }
 
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
        background-color: #e6e6e6;
        border-top-color: #e6e6e6;
 }
 
-#titles > button:hover, #titles > button.selected {
+#search-tabs > button:hover, #search-tabs > button.selected {
        background-color: #ffffff;
        border-top-color: #0089ff;
 }
 
-.scraped-example-list .scrape-help {
-       border-color: #555;
-       color: #333;
-}
-.scraped-example-list .scrape-help:hover {
-       border-color: black;
-       color: black;
-}
-.scraped-example .example-wrap .rust span.highlight {
-       background: #fcffd6;
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
-       background: #f6fdb0;
-}
 .scraped-example:not(.expanded) .code-wrapper::before {
        background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
 }
index 60e4e7492240c09c52d44012f5dda6defd2435ed..51aee8e7c899212193006655b56e51c394fb3c1d 100644 (file)
@@ -563,7 +563,7 @@ function loadCss(cssUrl) {
                 onEachLazy(code.getElementsByTagName("a"), elem => {
                     const href = elem.getAttribute("href");
 
-                    if (href && href.indexOf("http") !== 0) {
+                    if (href && !/^(?:[a-z+]+:)?\/\//.test(href)) {
                         elem.setAttribute("href", window.rootPath + href);
                     }
                 });
@@ -1040,9 +1040,6 @@ function loadCss(cssUrl) {
             help_button.appendChild(container);
 
             container.onblur = helpBlurHandler;
-            container.onclick = event => {
-                event.preventDefault();
-            };
             help_button.onblur = helpBlurHandler;
             help_button.children[0].onblur = helpBlurHandler;
         }
index bcaff957af2f60aa2ed651a9b464bb8374eca9d1..fddda293b9a86d98cf300cb1ebc672ae80fe1df3 100644 (file)
     {%- if page.css_class != "source" -%}
     <nav class="mobile-topbar"> {#- -#}
         <button class="sidebar-menu-toggle">&#9776;</button> {#- -#}
-        <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
-            <div class="logo-container"> {#- -#}
-            {%- if !layout.logo.is_empty() -%}
-                <img src="{{layout.logo}}" alt="logo"> {#- -#}
-            {%- else -%}
-                <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
-            {%- endif -%}
-            </div> {#- -#}
+        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+        {%- if !layout.logo.is_empty() -%}
+            <img src="{{layout.logo}}" alt="logo"> {#- -#}
+        {%- else -%}
+            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
+        {%- endif -%}
         </a> {#- -#}
         <h2></h2> {#- -#}
     </nav> {#- -#}
     {%- endif -%}
     <nav class="sidebar"> {#- -#}
         {%- if page.css_class != "source" -%}
-        <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
-            <div class="logo-container"> {#- -#}
-                {%- if !layout.logo.is_empty()  %}
-                    <img src="{{layout.logo}}" alt="logo"> {#- -#}
-                {%- else -%}
-                    <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
-                {%- endif -%}
-            </div> {#- -#}
+        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+            {%- if !layout.logo.is_empty()  %}
+                <img src="{{layout.logo}}" alt="logo"> {#- -#}
+            {%- else -%}
+                <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
+            {%- endif -%}
         </a> {#- -#}
         {%- endif -%}
         {{- sidebar|safe -}}
index d7184053c87a4dd6b5521e99e1cb6672eba102f4..56283b2c0eff9eb622d385a9f881dae5a52caece 100644 (file)
@@ -8,8 +8,9 @@
 use std::fmt;
 
 use rustc_ast::ast;
-use rustc_hir::{def::CtorKind, def_id::DefId};
+use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId};
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::symbol::sym;
 use rustc_span::{Pos, Symbol};
 use rustc_target::spec::abi::Abi as RustcAbi;
 
@@ -217,13 +218,27 @@ pub(crate) fn from_item_id_with_name(item_id: ItemId, tcx: TyCtxt<'_>, name: Opt
 
     impl<'a> fmt::Display for DisplayDefId<'a> {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            let name = match self.2 {
+            let DisplayDefId(def_id, tcx, name) = self;
+            let name = match name {
                 Some(name) => format!(":{}", name.as_u32()),
-                None => self
-                    .1
-                    .opt_item_name(self.0)
-                    .map(|n| format!(":{}", n.as_u32()))
-                    .unwrap_or_default(),
+                None => {
+                    // We need this workaround because primitive types' DefId actually refers to
+                    // their parent module, which isn't present in the output JSON items. So
+                    // instead, we directly get the primitive symbol and convert it to u32 to
+                    // generate the ID.
+                    if matches!(tcx.def_kind(def_id), DefKind::Mod) &&
+                        let Some(prim) = tcx.get_attrs(*def_id, sym::doc)
+                            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
+                            .filter(|attr| attr.has_name(sym::primitive))
+                            .find_map(|attr| attr.value_str()) {
+                        format!(":{}", prim.as_u32())
+                    } else {
+                        tcx
+                        .opt_item_name(*def_id)
+                        .map(|n| format!(":{}", n.as_u32()))
+                        .unwrap_or_default()
+                    }
+                }
             };
             write!(f, "{}:{}{}", self.0.krate.as_u32(), u32::from(self.0.index), name)
         }
@@ -237,7 +252,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         ItemId::Auto { for_, trait_ } => {
             Id(format!("a:{}-{}", DisplayDefId(trait_, tcx, None), DisplayDefId(for_, tcx, name)))
         }
-        ItemId::Primitive(ty, krate) => Id(format!("p:{}:{}", krate.as_u32(), ty.as_sym())),
+        ItemId::Primitive(_, _) => unreachable!(),
     }
 }
 
@@ -646,15 +661,20 @@ fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
 
 impl FromWithTcx<clean::Variant> for Variant {
     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
-        use clean::Variant::*;
-        match variant {
-            CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
-            Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
-            Struct(s) => Variant::Struct {
+        use clean::VariantKind::*;
+
+        let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx));
+
+        let kind = match variant.kind {
+            CLike => VariantKind::Plain,
+            Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            Struct(s) => VariantKind::Struct {
                 fields_stripped: s.has_stripped_entries(),
                 fields: ids(s.fields, tcx),
             },
-        }
+        };
+
+        Variant { kind, discriminant }
     }
 }
 
index 057d2fdd9d5fce5b568108af8f4c4ce4f71cc509..6aa2dda980cf31a14a41f014c76805a3c7692eeb 100644 (file)
@@ -82,7 +82,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
     let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.item_id.expect_def_id().expect_local());
 
     // check if parent is trait impl
-    if let Some(parent_hir_id) = cx.tcx.hir().find_parent_node(hir_id) {
+    if let Some(parent_hir_id) = cx.tcx.hir().opt_parent_id(hir_id) {
         if let Some(parent_node) = cx.tcx.hir().find(parent_hir_id) {
             if matches!(
                 parent_node,
index 995fb5dcc1c86de89b780320701190eb25c3790d..f8a0d77538d395f230c0c1a36338f9b9c38a8363 100644 (file)
@@ -132,7 +132,10 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             // implementations of traits are always public.
             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
             // Variant fields have inherited visibility
-            clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
+            clean::VariantItem(clean::Variant {
+                kind: clean::VariantKind::Struct(..) | clean::VariantKind::Tuple(..),
+                ..
+            }) => true,
             _ => false,
         };
 
@@ -245,6 +248,7 @@ pub(crate) struct ImportStripper<'tcx> {
 impl<'tcx> DocFolder for ImportStripper<'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         match *i.kind {
+            clean::ImportItem(imp) if imp.imported_item_is_doc_hidden(self.tcx) => None,
             clean::ExternCrateItem { .. } | clean::ImportItem(..)
                 if i.visibility(self.tcx) != Some(Visibility::Public) =>
             {
index d29ceead4f3a549026a519f8ee83a83695ae6c0b..390b9436121951206463db0210b4f407609c1c2d 100644 (file)
@@ -17,10 +17,10 @@ fn visit_inner_recur(&mut self, kind: &ItemKind) {
             EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
             TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
             ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
-            VariantItem(i) => match i {
-                Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
-                Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
-                Variant::CLike(_) => {}
+            VariantItem(i) => match &i.kind {
+                VariantKind::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::CLike => {}
             },
             ExternCrateItem { src: _ }
             | ImportItem(_)
index 310a01194eaf8744e1e048417309b8a3acd1c18b..7db470359672f834fdaff1017f3a496a5979e28f 100644 (file)
@@ -410,7 +410,7 @@ fn visit_foreign_item_inner(
 
     /// 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 into the list of modules of the current module.
+    /// add into the list of modules of the current module.
     fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
         self.modules.push(Module::new(name, id, m.spans.inner_span));
 
index 3dfd4d93fa013e1c0578d3ceac5c8f4ebba4b6ec..9ad24035fea8d309753f5e39e6eb53d1d0eb39ce 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3dfd4d93fa013e1c0578d3ceac5c8f4ebba4b6ec
+Subproject commit 9ad24035fea8d309753f5e39e6eb53d1d0eb39ce
index 1ee96b8231cd1418349c17977a645c44d2d75a2c..387d5787dfcb25fe0348bd0daf998796595c5359 100644 (file)
@@ -9,7 +9,7 @@
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 23;
+pub const FORMAT_VERSION: u32 = 24;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -333,11 +333,18 @@ pub struct Enum {
     pub impls: Vec<Id>,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Variant {
+    /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
+    pub kind: VariantKind,
+    /// The discriminant, if explicitly specified.
+    pub discriminant: Option<Discriminant>,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
-#[serde(tag = "variant_kind", content = "variant_inner")]
-pub enum Variant {
-    /// A variant with no parentheses, and possible discriminant.
+pub enum VariantKind {
+    /// A variant with no parentheses
     ///
     /// ```rust
     /// enum Demo {
@@ -345,7 +352,7 @@ pub enum Variant {
     ///     PlainWithDiscriminant = 1,
     /// }
     /// ```
-    Plain(Option<Discriminant>),
+    Plain,
     /// A variant with unnamed fields.
     ///
     /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
index c3f50272b67c2edf648f79bf129a72cc2b6398c3..6a389a64406f9043a746aec08dd69a9acad3df6d 100644 (file)
     "tool is executed."
   ],
   "compiler": {
-    "date": "2022-11-01",
+    "date": "2022-12-27",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2022-11-01",
+    "date": "2022-12-27",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2022-11-01/cargo-beta-aarch64-apple-darwin.tar.gz": "ebc0b11a2af0385bf11a5183dc159d890161be45d231acc34c6326aa25b84b95",
-    "dist/2022-11-01/cargo-beta-aarch64-apple-darwin.tar.xz": "a0e44bf77337518e2200c34cb297a91dd4db51f0d331ca4cc496989da61676b3",
-    "dist/2022-11-01/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "a4beae1c53df4d35fe991ebc713e37246d4d89e5543ec740274605a7124806b3",
-    "dist/2022-11-01/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "5f8ec5c8b012d7e6bc28ca3d700c1c7c742f6532adb044539cee3b2280c1056c",
-    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "54d8fc5ce70b1f06164e17e34d33abde7260c6b1f3356d98d77271ec89766fb1",
-    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "f2debb6ae264fefc49380997759bb0b5022ac1c65ced9bc17bc146671be37116",
-    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "7a8e10be17c8cd624fb3ae2bb7eaab3c493b637c2c1c1100b5333982d1dfd962",
-    "dist/2022-11-01/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "553decfc64b56d9967ae067bc942ef7117c81d6976b5fa4cf8e5171397836af7",
-    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "64bdb603cdc05b983393d707e9e6e6cd1c71dd8213d08b3d0d1cdf168ceb165b",
-    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "0afe4ca54c65668257dcad5941c678498ab917bbf82a808f39c093719a53f2ed",
-    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "c7fe3bacc9c4acb9b42677281655904b5ed5aec27042b9a8cf9743b737b6b657",
-    "dist/2022-11-01/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "57f985ccaa2452778c90733e2586a991969dc15697bdbc9547da8a62c871b674",
-    "dist/2022-11-01/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "873b2a0c2990eef29d689984293394e6972b4659bd6e4c31fb9bc9c8f1c679f9",
-    "dist/2022-11-01/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "f8a9e74159594d57ce8dda1f7ce7ee4e1d494b9135a0f32b3afc89a637cad8ae",
-    "dist/2022-11-01/cargo-beta-i686-pc-windows-gnu.tar.gz": "9570141b118c2339237aac12c1e6d71c138ccef784db2effdfd9d02fb12d0d0d",
-    "dist/2022-11-01/cargo-beta-i686-pc-windows-gnu.tar.xz": "183b63cded6c4cc26feaa14be036a619289b155a6718f4964f94c38a9208742b",
-    "dist/2022-11-01/cargo-beta-i686-pc-windows-msvc.tar.gz": "9382bf364c5fc9400fb22b046c0a951001961efac221f5cd0f9bf45b1005d36e",
-    "dist/2022-11-01/cargo-beta-i686-pc-windows-msvc.tar.xz": "aae0a58b9711365ce1d76966af7387f310b496859a9e02ddbff8e23da93226c7",
-    "dist/2022-11-01/cargo-beta-i686-unknown-linux-gnu.tar.gz": "507727f9b5a920ea28e7104c9aae681c50fa8aaea446a3e10b991a9408adaefc",
-    "dist/2022-11-01/cargo-beta-i686-unknown-linux-gnu.tar.xz": "4ebfaf11ffc346eec9f05b2d93123483b784b83a322cca6f5fd406066ecf0fcc",
-    "dist/2022-11-01/cargo-beta-mips-unknown-linux-gnu.tar.gz": "6407889854bee2e45a00585abb4fc8b387103e33e3e67244dba4e140abe46480",
-    "dist/2022-11-01/cargo-beta-mips-unknown-linux-gnu.tar.xz": "1aeba894f0ca756dd9c3d9b99c7c94bf1f49d5d87ea919249fd0fcf195eb9c52",
-    "dist/2022-11-01/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "292a95a8de3387832173d9adde633b3d34a019879f97bf196cb41556c3909337",
-    "dist/2022-11-01/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "872819f00ab0a848401d7dfbb18cf139f85b3d8e48eee0a034cf7f0b970bd865",
-    "dist/2022-11-01/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "15eb49c334688e48e83f2565c620b3f1af29775599406efa1814c78ee80673cc",
-    "dist/2022-11-01/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e74f6884e71109d36d03f7147b7e506f374ba291aadbe4246f6c429bd6fffd1f",
-    "dist/2022-11-01/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "7f3cf8b35465e4df5fc18cc7cb4f4db6e1b240a39f7583126d7f8ad6d18e8bf0",
-    "dist/2022-11-01/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "c59f2893999dd88a55c0a5bdb4436640ae9c18f943baf48f63eff6069f7a3e8d",
-    "dist/2022-11-01/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "566c315b6206a63bf33acf178547bb757a8803e3cfc71f1f63ee033eb6a17138",
-    "dist/2022-11-01/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "814a8e8f8f5caf5bb4018e54ffc2c1bd9d23df94dcaffbc04881b91bb3c8aefe",
-    "dist/2022-11-01/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "5db8a63532be5fb9511238d7976075496aba6c732302dcc27bed9ae61188f917",
-    "dist/2022-11-01/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "6b95c8cc4dda3847f53fb62ea711ca99c1b1b1639249b8b01d54a9ecbc4421ec",
-    "dist/2022-11-01/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "2ad497be28760f7e4ec6dfa6421a6c10ab049e0dbf45ecb3a2dbde5db7a959de",
-    "dist/2022-11-01/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "6e9b982857c64518c10392779528e7065191262a95e091ee289c8668b6cbfc4c",
-    "dist/2022-11-01/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "88a0751ef36816f9e26e9f6d72809687b1f6821b32a3a17c58feaa32f882aecf",
-    "dist/2022-11-01/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bd6f626002a0c5a3af975419a1258a77c9db91e0db5d4acccbc7dbf25ffd17c8",
-    "dist/2022-11-01/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "69bad5758f27f53d3e48abcd5aa70b16eb29d5445233c65ab50a8ad0a1629077",
-    "dist/2022-11-01/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "06212f4cb605fb79d811060d3096bc4b43cf00e1a4fe4a375154b56ff60c92f5",
-    "dist/2022-11-01/cargo-beta-x86_64-apple-darwin.tar.gz": "741f3490b5562afd57cdda846ab322c69e20940bcc11f3ca5690d662d5de280b",
-    "dist/2022-11-01/cargo-beta-x86_64-apple-darwin.tar.xz": "2d698df7c00b7c227ca388830732a8787b2a85b328b554c0f8c417813d97ef46",
-    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "9c22b476f25c3f0946cb834da3904516248137cf22c5eed30432401ff061a4cf",
-    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "1604c5d60379227d26d819bd2f7a57c79a9e000a6077ec06e95b418bb0351180",
-    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "673d8941202c2113a431fcef396e604d7ea79000c97a64ef6e93b26956f75fe7",
-    "dist/2022-11-01/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "3d613d04b48a2eb8644e2bfbb07a88cefe02c7b5cc7bf061b8ef307980230d47",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-freebsd.tar.gz": "e0ce6fa69af565e3b79f7059a4de88e39955d7ea6866d56c2b0946b47929192f",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-freebsd.tar.xz": "de602b7802b1448a861df05c41430dcde4f07358a05711784a1ca37836525b74",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-illumos.tar.gz": "c4eacf4821c126b321a67e0233d2f84571b3dcf25686165cad00d9645787f03d",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-illumos.tar.xz": "01ec5ab637010498b784ea2fe6aacea626fc341792eaa5a50756f9b483a765e5",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "2e6efadbcf138ab72750c1375bfeaf2d5102559aa9b745294b9973821e193703",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "e089b1b4248ad8e05ba54cfb278101a74aa34154bd2d44dd50119026bf436d1d",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "ca079fce260accce11c1fb27e550421cd0900027e29b18e24e54a298d78031c3",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "ff33e9fd6f06e02277f580f13d82f753987f4dad7d7926405b63dcb362eec498",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-netbsd.tar.gz": "46101fc5f53595ae53f3ceb755cc72c078471479a337b5319c85e629e5df3b28",
-    "dist/2022-11-01/cargo-beta-x86_64-unknown-netbsd.tar.xz": "b063425ccc69284e8788211bbde5a7843bd16a3b9c779fab68a11d22ebdf319b",
-    "dist/2022-11-01/rust-std-beta-aarch64-apple-darwin.tar.gz": "77bb5db904089e087032c24fa2e011536e13d3982299285a7515beb97f445078",
-    "dist/2022-11-01/rust-std-beta-aarch64-apple-darwin.tar.xz": "63aae4b9f10f15fb48b2ac20aa7f112a685d49bdf94d8997d036472e928fcbde",
-    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "8f63b6be668e6a25411582db9145c9de8192d58acb42c490b0de89489a3e36c6",
-    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "d862bdeaf2c78b15babaf74cf1c6feaa5c4871a90095f3d4239d81f44217cff4",
-    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios.tar.gz": "e5b1e9420d387a1442c77bed10efebd7b0268713820a728a067bb4ead6088041",
-    "dist/2022-11-01/rust-std-beta-aarch64-apple-ios.tar.xz": "569c667e422ca7ac373d59b6e13c299cdb7f334164c84e6f0c8d0f076352fbf0",
-    "dist/2022-11-01/rust-std-beta-aarch64-fuchsia.tar.gz": "3f945c43c09704b3df6af66a2132da12243b13752094383965d6a8a83c6edb0a",
-    "dist/2022-11-01/rust-std-beta-aarch64-fuchsia.tar.xz": "3662f02892ab184be99f93a9d0f99e030a73cc61447934b74fcba84e05b022b1",
-    "dist/2022-11-01/rust-std-beta-aarch64-linux-android.tar.gz": "ab04a0228074e974d70a15e594d57479fe22ed37c8acfa5104201dbbe57747a7",
-    "dist/2022-11-01/rust-std-beta-aarch64-linux-android.tar.xz": "fb96925878a24dc9e90d356e96cf4fd1fc9152c39f8914f9a9bb676d78069cba",
-    "dist/2022-11-01/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "45e824f75ac530ee9eaf0b0a01cacd5b8dd64ddf5203c032c49fd2bc4fabb245",
-    "dist/2022-11-01/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a6488faf4c87cabb4467f4cbe7348d553045c2f10f450bc6e000fcf18ca9b073",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "e2a66e04b24aad8a8898d6c0270d8dcff63205213cea3b893807ef186e8c0936",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a4244ac1600726b5abe6b5f9a171fc2e4cc57bbe7cecdeaf23b69e906f05e303",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "9e3e0f675ca50b7a2a1afeacdaf5d7f2f4ec1536f596ff99aadacfcb59fd42f5",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "7e7a8fb4fe0283b71deb79c5ccb1ae61b2099392b3c8e09d03d4a68fbab7a184",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "7543df1d71d805b079d19ccd785f777918b3f11b131bca05d079cb5d3952a38b",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "eb082e894047cd77ac3fcc9c03eaaef77e6bafbd075cb0d62ba3a3ba277f5d64",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none.tar.gz": "144fc6973b06ffb12b5ad0bbfc9fcdcb2a0732de50bb140d62d6af3d6b462908",
-    "dist/2022-11-01/rust-std-beta-aarch64-unknown-none.tar.xz": "8ee2ba2d4eca35a426fb089e0f0b50b2ac3ad1ab036c5f8f4786e2953405092f",
-    "dist/2022-11-01/rust-std-beta-arm-linux-androideabi.tar.gz": "4a46d6591c1983d0853f7596f7b76e7c82b6b0cbfd97802b565a17aece0d13be",
-    "dist/2022-11-01/rust-std-beta-arm-linux-androideabi.tar.xz": "3888fe036b5fa9a5dfa009462a002a05c70e56eb70db3a0c872fab1432e9c9ed",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "529d668389506443f87bd93e98dc72d12be9a4ab41675dc6a1c7373e934ca017",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "dffa1a94f4166435d6fe2a76a4d35deb8c128cc93146f181979416816e77e29a",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2913bc06d6b49c52804a8dc18d1d3cb1b564e0272cba93f8594747731d360f9c",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "c12bb97fcbeeb0a9a71b2575b2d5113948c515616f720dae3891e2aa886d03a7",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "a844ad8a80fa07b9196dc040d5171749daf94443c57348bca04e69b8dad37cba",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "c261662fa988748ed03722d6034228c893e02a0e473f906bba61c1f43be7cd79",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "1ae5967f4fb80047711519dafea21fed8d6afd308566033e468c11587073d216",
-    "dist/2022-11-01/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "150393cde94d8349eb488a161572589c53fed456c8401e5b1a59d1dd87003f7c",
-    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabi.tar.gz": "b1777a389e4db0ccd80ece774865bc99731c4b483be80c909f1b5a2a185dc5a1",
-    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabi.tar.xz": "877a00491650bac92e93760c2457b644d2b5ee28d410c1e29fc4b40c05da493a",
-    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabihf.tar.gz": "3dfbf001db319a41874e2c0de2f55407285d88156fa0563cfe3c3bb1939998fb",
-    "dist/2022-11-01/rust-std-beta-armebv7r-none-eabihf.tar.xz": "b2d6a543cdf64a5c147001ea30d07bd13b98e2918a343bff08bb57eed1f81462",
-    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "cd8f0803ef86052d09606601b09dde05d1997a93fad7a22604fda1176157040e",
-    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "748cef6595fcd30da6735c29476639ac80cba94eb627d6654665d656da2979ec",
-    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "1dcae3588a3e552778ff1079a92750bee15835f08f8b9ff1123e4e6c5a73c087",
-    "dist/2022-11-01/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "3711105029d28fd91f413f488b7041ea42c70e5a244f992e9259b4e9d52abed1",
-    "dist/2022-11-01/rust-std-beta-armv7-linux-androideabi.tar.gz": "a2af3f6d3681e1c545d0c21bf04fbfe3de1cdb2273fadcbbb4408f5590054d11",
-    "dist/2022-11-01/rust-std-beta-armv7-linux-androideabi.tar.xz": "23e658070e1cbe8011d48678f57bedbbde819cd64f43509858af563a7073a3fd",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "ff7b429d5a6d33f0e467b333225f7c42de279ccf3e91f3ef7c5463dc06939579",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8d41b293656c5cf93f46754499e5723a89dd997d3723bfbe56f953a7d864c435",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6dd89ed0f20a0ea4a279dd4f810c7908c3e8a377da8a2983f8890efeea169177",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "504fb533fca6c46ad98c728781ab31170d65e5b35cbc9199aab97b1146a24702",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "f9a731fd3ea961f0c5eff24e6290aed19d79d5444bf562670abc0cd46ee309fe",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "825acb16e4bbba0c9b535e635b972ec581fe6ef115c5a41bace9b85c704eccad",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "41da8404f0e3cef386f6efef9b27fde27de77de71140dceeaddd8e15260ce45d",
-    "dist/2022-11-01/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "c8f81fa9cfb40ce92f2c95ef8b57e8a62d819628111e1dfe0c6760fb48802be3",
-    "dist/2022-11-01/rust-std-beta-armv7a-none-eabi.tar.gz": "fa8c3168dff5c167c6ed25f9c605941ab51e73e70c0dd162a5fd17287c5fd5a5",
-    "dist/2022-11-01/rust-std-beta-armv7a-none-eabi.tar.xz": "36a5ff7865f8a16b867ab3fff4ac32f0c62c260a5c27385098e67b75b21790fb",
-    "dist/2022-11-01/rust-std-beta-armv7r-none-eabi.tar.gz": "0417cef6468fd66bf626729e7c0089b47b149cfc43e8e0d4281f76f73ed17edc",
-    "dist/2022-11-01/rust-std-beta-armv7r-none-eabi.tar.xz": "1de6cb38a68ef336e1edf2c1c51d999482898df99e2bc078cafe6ac5380bf3f2",
-    "dist/2022-11-01/rust-std-beta-armv7r-none-eabihf.tar.gz": "91003d4648fb01306d6e0a0214e089d444a57c5ff09138040f07cc81e89af639",
-    "dist/2022-11-01/rust-std-beta-armv7r-none-eabihf.tar.xz": "884306ac77518ece0cb2f22d898e3d2aa50698bd4181ca23a1dada6d82778682",
-    "dist/2022-11-01/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "f17ca8f54eca5d73006659fd08142d537eff23731b6e5a35bd67efafe0dc8cb1",
-    "dist/2022-11-01/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b04a17d33d7b9b1caae666dfa5ee9a98e5dc079773b6345f6c49733731e14bfe",
-    "dist/2022-11-01/rust-std-beta-i586-pc-windows-msvc.tar.gz": "55e61aa74bdb50df54394a0f62b9edc88682c37b51fe9d8d5c05c0619eacd1e3",
-    "dist/2022-11-01/rust-std-beta-i586-pc-windows-msvc.tar.xz": "ec3d887742289ef9c171ae56ca20c3e9cf1972cc3e6c511611404070c55dac8a",
-    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "a36444f0ba0e7e03d06fbf65d830cb7067c675ed061e8f6efd6ed445d5955e88",
-    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "dfc07297ee8cb63f76d2019ae822352e6b42e5cccd225eaa5597a63ecff3624f",
-    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-musl.tar.gz": "e8de9f830cf277be584b54d86d6621a249fb2987fdf32d5f16cde9b492722d45",
-    "dist/2022-11-01/rust-std-beta-i586-unknown-linux-musl.tar.xz": "f9d8bd74788e2209ecb8d0cc49d94b4e2752c9239f89bcdff3e8fae315d1d923",
-    "dist/2022-11-01/rust-std-beta-i686-linux-android.tar.gz": "b15636654925fdba1e9ec1704573e4af1fc5f1158a0657b245901e22c06cd378",
-    "dist/2022-11-01/rust-std-beta-i686-linux-android.tar.xz": "9abbfcaa40d86e8a4cf49f2a58b1c7b2f422b6890303cb43feb83cfb8f650a42",
-    "dist/2022-11-01/rust-std-beta-i686-pc-windows-gnu.tar.gz": "30953eb457a397966221dad058ff7ebd99ca4497f184016b5a61db0f122bdee9",
-    "dist/2022-11-01/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f9d6d266eb3bb46c058615786483d817138aa29efc3c62c3cd9c87e572956b12",
-    "dist/2022-11-01/rust-std-beta-i686-pc-windows-msvc.tar.gz": "b55202c349a4e9a493a2de7a3d48788befce32274998d3dfc1d1b6f4a96ba9e3",
-    "dist/2022-11-01/rust-std-beta-i686-pc-windows-msvc.tar.xz": "6dd8d42e5712d699704e85bb90cd42e0142a4fab7cf7f80132cb0902cc415ccb",
-    "dist/2022-11-01/rust-std-beta-i686-unknown-freebsd.tar.gz": "d2a7c9e7f1dba3a317692a46f8efec8d7ba1e9e943c88d3f342a820c34829aa0",
-    "dist/2022-11-01/rust-std-beta-i686-unknown-freebsd.tar.xz": "ecf6abb631dd6887b5630d1ea0b8778fc1539405e6c00d7585c8afa2230ef9ec",
-    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "93c5912258a49a003a12ca01101f5935d5894f9a133301a47047cca934a7439e",
-    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "f8a6e67723cb968e874827a6148a5e25d3d45c56577faee627010347d0f03d92",
-    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-musl.tar.gz": "8838592167a8d68f463dc18e55d5d2d55c474426e8a4ec0f28fd2cd4230cf638",
-    "dist/2022-11-01/rust-std-beta-i686-unknown-linux-musl.tar.xz": "c8330a06862a7f375b57774b382a54a1280c33ddc1b94d5d5ec45eb6ff0de8cb",
-    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "4b50cc174eb1da9dc831de828e6ee2fc8a81abf8e6dd52b041e4ab00eaff73ac",
-    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4820db058569be7350a81396fdedf9a28233b8061c9bcf607cf2d1058cbf437a",
-    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-musl.tar.gz": "dfbc460e8322114bde5614b0b45e90066805adbaca999ccdc4f2aae456fc3f1f",
-    "dist/2022-11-01/rust-std-beta-mips-unknown-linux-musl.tar.xz": "d98c19268b0c84f44f1224f432847a93eb809a85ca48fbe2e4b68fb436bc36aa",
-    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "8617edc6d62591d50dbadc4a7bc41b31b66bee6fee830af46636c5206027217f",
-    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "98a6132c8dd7558eb5f44007fa681a3a91b2dfd98d1f68e59f0a4660dc37b500",
-    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "81f794c54d7a8c680c52a8fc1a0e479526744205d51266007fc3c542496957ba",
-    "dist/2022-11-01/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "dedc5b1a76f8454d1b3d7fda0a05398e5a9ae4cf16ddc4b44477799217a1fb75",
-    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6d9b3d469ae92e38144d9578de8cf0c891e4bf3e667e4e465eb6f0d498140c3c",
-    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f9deb84c24bd0f21ed02d763d3ad8dd92c009de4ceb2b78ec06d90d66609c5f6",
-    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "073882815493668dd484b8f107efc047f6e07d8c563703d0e7f73ef33dae0efc",
-    "dist/2022-11-01/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "d1ab3758d1b08937a3f98737ff9fad20377e5bc43d7ab3a9359b4131ea11dcbc",
-    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "bc82f3d23dfb7b331558180f474c334ca3798322e19cc64657cbe894d0682901",
-    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "fcc12f82ea0c02e8434420165f1ee072bf4587a82ff5ecf34d19f754ffc091ef",
-    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "1c4507c7824c02b1af2857c88ff1624e9ead3f38c1456aa031586b43223e9490",
-    "dist/2022-11-01/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "932598fbcc35ee4958be4778450f5b809ce9eabb2aa3d7573fd79744ed4d18ad",
-    "dist/2022-11-01/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "c17f11707c1edef2353fba7e3f4800cecb8a273233825817b6d07ed78d6acd50",
-    "dist/2022-11-01/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "7e90a819b8887f0b1a3ab02fb9a56a9b9eb752408a7bb934c99c7f6ddda48a71",
-    "dist/2022-11-01/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "c437a6fc7cd7869df7cdbb52c51ae1e602ed1206517c38689deb73da6d7b4877",
-    "dist/2022-11-01/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "76c1fc55b16a809ab1c8dfce894899f40d24b20dc670d318a7679953beb6c3a1",
-    "dist/2022-11-01/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "d62396390fb85d5543a80ffbeaf7c32b5297a513dce14790124c35835813032b",
-    "dist/2022-11-01/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "4595485492c650aa53bb9deaeb425ea956f2052c5b5503bb477778f7bcaf6ac6",
-    "dist/2022-11-01/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "ee841bb8fbb0075a0bf51db2007bee2962830a89649c00fd15c67b31fd9226a3",
-    "dist/2022-11-01/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "cac036fafa93f2860a5a2622394e12938c35e629ff81d7cc5930d99c980f9321",
-    "dist/2022-11-01/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "025d70e57d608b81d61799c84ccce9bca3603736c4d3e006fc662c3a7b39e8db",
-    "dist/2022-11-01/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "9450b1b1f95e188bcb9050085d612c8bef36e819881255fc20d70da1f45fa61e",
-    "dist/2022-11-01/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "ff707c6d209f9d8e421fc530a11d41a46daaebdb4aebd5cfbaab761b2cf192ff",
-    "dist/2022-11-01/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "8eb48a94c58440e2afc8ef7bbdbc725f403fe38724c0afde4e7c29a1ba2c7591",
-    "dist/2022-11-01/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "e921a841b7a9e02e28182e91c921746042330d90f0478fc7e01230cb1b881c1c",
-    "dist/2022-11-01/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "122135e161a4cc7dd857e3cb35b64ff7db450dcc07cbb990c8aa83e06bb4b346",
-    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "084824d6daeca6a0662ef1e11df84c651138d8d4e7d5c8ef66c5811354b16211",
-    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "09e3df606e10a0a59a67bf7b49825a04c23062e6050cebed674e0bdb2c396fcc",
-    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "f9929f62ffec9c6b3342da8dd21b1c14526e033174a4f86015182acdbb93a985",
-    "dist/2022-11-01/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "932450fc6b5e8fa4813886baa389b53c6ff1c5b1e71f7370017b9658b04fd13c",
-    "dist/2022-11-01/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "e7776d188a04779e7f6a7257bf367d8671e7d5d804d74db426592f683cabf562",
-    "dist/2022-11-01/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "bbc765adc116c6a1bcbf659853b7169d95b240ffc15227cbb1d60b46d63e120a",
-    "dist/2022-11-01/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "a0ff6e9ea827d7f93563aaec213eacd00efe4be9c921b448405b2af8bbf0066e",
-    "dist/2022-11-01/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "7603744cbbbbdec5b2a322aabe68751e848ac7379c710866c59dcc22e4b873bd",
-    "dist/2022-11-01/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "1f67446eb09505e87a5218b8504dfc678d0a712a5add763362f3c74306010bea",
-    "dist/2022-11-01/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "1baca6f0e7f18a8eb9efcf35bca4320a493d51f08e62bf96a31036e2f2c433fc",
-    "dist/2022-11-01/rust-std-beta-sparcv9-sun-solaris.tar.gz": "455e52fa3f232c2239112030483c0a657e7f69754d8d36ab72423c76c056fb68",
-    "dist/2022-11-01/rust-std-beta-sparcv9-sun-solaris.tar.xz": "913801ca45eb1d70c9ddfcdd66aa21edaafccc85acf9864e88991bf8a5a7cf25",
-    "dist/2022-11-01/rust-std-beta-thumbv6m-none-eabi.tar.gz": "14e4f69fbf710f16275ccb582a90eee1399ea1226945c7c96f75335df9118966",
-    "dist/2022-11-01/rust-std-beta-thumbv6m-none-eabi.tar.xz": "40549d9d9c923a73381b8e45628cfa1896d0e78caabf2aa921c767e0bc979136",
-    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabi.tar.gz": "d40bd56883abc142155188674580c4e29100fd7303fccc70b0c55b964721a156",
-    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabi.tar.xz": "874c97a01d06e1516a89797d7a6effeabf34afb4933956aa34e907a65ea78690",
-    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "cf7acd2b4a083522c01f1909891aaba27502ea0a3a5eff93dfb41971f832bba6",
-    "dist/2022-11-01/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "e9544acbefa3effe55537de85311b00077a0567d64345aa80414752037212b5f",
-    "dist/2022-11-01/rust-std-beta-thumbv7m-none-eabi.tar.gz": "247e9dae16f46c64da895528f3e902030110e2aad8270f169c636ca14bfc28aa",
-    "dist/2022-11-01/rust-std-beta-thumbv7m-none-eabi.tar.xz": "b7de9e8bf7b7d04fc9575390d69eacbcc62a39c35c81f37d2170424cffe6a356",
-    "dist/2022-11-01/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "bd3dc986a11967e8ed050a88d03d1c0814b08cc1ab0cf929561fbf5a941a335e",
-    "dist/2022-11-01/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "262b4c4ccbe20c9e913a7417c8ca72c6fb7e71f187103929057dcd0fc0b49cea",
-    "dist/2022-11-01/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "85f6a725e5a726afab9ae019944567b42ee769db98a8d3c335d449eca92344e0",
-    "dist/2022-11-01/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "07e897f4320f249b3f458e44e5440591962105a3b6032b54f4448c0bd21da964",
-    "dist/2022-11-01/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "e92855841ae93990f88f3893a1bf511853fc3f10938eda767d5c7ff7d310aa4f",
-    "dist/2022-11-01/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c3412a67f769ead9e8bafbcb5ff6dfc8ef89f0d8234baee7b39ab9df9fadebf",
-    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "f3cd623fdd466e5c0b5749dc4e90a75122f1989f6fcae0ace8c76f3b394a0752",
-    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "3793ab2a42f1bc59ad560ad1af75ed90c49e25f665330b5b8ce50ed73ef88508",
-    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "cc6c715e320c7fc5fd90f446f7c2ce6b356e95934d05f79c4e2d0fc304f212bd",
-    "dist/2022-11-01/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "42a47ce6768b24c2b40c6a724003a401bfb37201a773e3c31ee413cc559cda70",
-    "dist/2022-11-01/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "4c09e5b03a921d8c1d8a10d9535e81be3b3bbed961d229311cc691396ae10cbb",
-    "dist/2022-11-01/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "775f7223bc5d962b5356a4884565a948d3cb5289fafe3e2eb2b8ad67550d72b4",
-    "dist/2022-11-01/rust-std-beta-wasm32-unknown-unknown.tar.gz": "bc027d9170132c36faa47da1ff8f26d26d383a5145cb9dd2dce20e769ea300ba",
-    "dist/2022-11-01/rust-std-beta-wasm32-unknown-unknown.tar.xz": "9a721d3550132930820d9b809074535d2b63ecb91d5c061effded92b503bf0c2",
-    "dist/2022-11-01/rust-std-beta-wasm32-wasi.tar.gz": "047d58ef5e10ab51a81dbc11646fca184945a1c52e7a91552449c67952c8d898",
-    "dist/2022-11-01/rust-std-beta-wasm32-wasi.tar.xz": "a490ce6ebc77a4a49c2fdeec471dd9e586b2aa26f1e7f2fc1323cc06b2b336d5",
-    "dist/2022-11-01/rust-std-beta-x86_64-apple-darwin.tar.gz": "df73bc81d446792d9366772944a04f69ad32f427e1949e05d4f7c202c350c269",
-    "dist/2022-11-01/rust-std-beta-x86_64-apple-darwin.tar.xz": "450aec3ec53594869bbf16ffe1713dfa19b8dcadd812a4af811bd56f1f58c929",
-    "dist/2022-11-01/rust-std-beta-x86_64-apple-ios.tar.gz": "fb698f63336a186983b09c2c49109dd080c22653f3367dabfcbae564144aff35",
-    "dist/2022-11-01/rust-std-beta-x86_64-apple-ios.tar.xz": "0d475ba4a4444f4da5fb39d26c9cdbc0352ea799d7e30f57e2e79d8c3c7a7021",
-    "dist/2022-11-01/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "137234fc37b93ef4fa543f4e33217079137b4dbb51efbea669b93e561932b5e9",
-    "dist/2022-11-01/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "01e1978d9359a5112aa77409ff17c3d0e0dec774815f679065db6c6293aaa623",
-    "dist/2022-11-01/rust-std-beta-x86_64-fuchsia.tar.gz": "662e62862b1586f29372339319680c88b7cebe41e98401b5dd62e320755f0d62",
-    "dist/2022-11-01/rust-std-beta-x86_64-fuchsia.tar.xz": "4a644c6c85c8e427d68a669b0f598669023e2c0db2b69b94a7124c18772052dd",
-    "dist/2022-11-01/rust-std-beta-x86_64-linux-android.tar.gz": "752a57eb3de0060c1ffc6eb0af71d88d5f881b543b11b209593be2b18af1f902",
-    "dist/2022-11-01/rust-std-beta-x86_64-linux-android.tar.xz": "19effccfd9d63e955cb0736968c4c300c6d919217a64cde464c30a499ae9fd9c",
-    "dist/2022-11-01/rust-std-beta-x86_64-pc-solaris.tar.gz": "aa8a36ec1892c68a1c1ea0d9ac1b92b03c975a0d8ee538aaee5d757ad84d5b2e",
-    "dist/2022-11-01/rust-std-beta-x86_64-pc-solaris.tar.xz": "955ad79007d397a9e24d819e95017880b25424bdac01386cb8fc6d50247b1274",
-    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "9f15bf80a2384f2fd333dee41289fdd8529170192dcbdd8cba0a73d32715ccc3",
-    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "539bcefcd6b888c5f38abca47792dcff1676ef31eeb9a4a045703582262758c1",
-    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "748fd22a993be659f85c3799871c4de09a99fcd7805c6d0e9d5a18dddfd2e26b",
-    "dist/2022-11-01/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "68c22dfa2ef5ecd2d43661716e8a8394eaa36e8e960d34dc421bbbe57c3e0d23",
-    "dist/2022-11-01/rust-std-beta-x86_64-sun-solaris.tar.gz": "f06118445fc6671d491c61dd8e6ff83ca21fc1d692058eea072cbe01ff798fb2",
-    "dist/2022-11-01/rust-std-beta-x86_64-sun-solaris.tar.xz": "b3fdd56baadf3a8bffd17730d61b2ccef25ffa25d5cd826bb9a45940bf573fb5",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "2dfab0336a523182d200c7a6096fb29c199339b282ba03b469a9a1e5c5a5bb0b",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "ee5b9158ca0c2e829bb79ac526d17a2ba27ca4e305e134241ba1f8347a9bace5",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-illumos.tar.gz": "fe62b766d11e9ac55db5011a63086af5d87ce560c0656dc214c668db752675e4",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-illumos.tar.xz": "e4b1068de2812c62e7ac0ec080f605fa90123a94563dc4f898221275fbd5178b",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "c5ce6885405ba4d1694a7eb767837320ece5a02133e94c1c22ac07143d6f752c",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "eac46cc9200125be2548d6b9f2c2d37b046b8b43b25dd7f7347d88ef6795a3c7",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1b3d1d051cf355eb26bf9de5096d984f83dc92fdeab3bdcd18d88152c0e2a2bf",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "a17cf4a9df1b1be17f5163f05665bc40638e62210d8e0623fb1afeeb96acad2a",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "90a2e5712bc37f28a0d1f71c54cc04233049c638e4f0592b50adea352e21038f",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "ad76d090357f5e272b1598c35dd24137fb9950e1bdc50b9332fa1d2fcc33a00b",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "37e0954add559b24c08ad284fb80294e435491159db63ea78a6183af5926dcec",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "d6542bd592edd3924999e690416b6bc559486388add76fa77044114b70700fac",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-none.tar.gz": "d021e49b68b8321354d99ae0fe80a6b042ec798ca7fe37cc92d4f0c0480f7ebf",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-none.tar.xz": "f6202c50c6d3575fdb398a8c98adeb0d86794b60c3951887c90a9e4acb6a89c0",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-redox.tar.gz": "b8ca678975c0c18d0fda1bb118b35366d1261e366639b8bb455b6bc59388082f",
-    "dist/2022-11-01/rust-std-beta-x86_64-unknown-redox.tar.xz": "119f9e65dc3484f677064e068da42a1e7b8dc0be21d0cbf5185c9836589b39be",
-    "dist/2022-11-01/rustc-beta-aarch64-apple-darwin.tar.gz": "11aa79c56a9dea2d5305ed049485a1257912fc0dfca1feff37b768971f4c1701",
-    "dist/2022-11-01/rustc-beta-aarch64-apple-darwin.tar.xz": "a031051ccf97100bd8b4d2e4df7a67371cdf300df4697e1d05a7cec33a7d8c09",
-    "dist/2022-11-01/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "4d015042d7d06929488f607bc56d925002e6f352d74fe192dc30e7feebb9947c",
-    "dist/2022-11-01/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "d72824112c96514d927df46f6e755898d26ddd5b805f6c2c0411c773105ad61f",
-    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "3e70261ed7c130cb7256717cec0c37476961932be228e46e028818f9076dfccf",
-    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "452f07f63888cf27ca2d061751602bb07a43348eca9cab30db27940a36f496e5",
-    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "995a6410305d43234eb94710ddc251bafd9f5fe4ecacc51c4dc1447f364be30a",
-    "dist/2022-11-01/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "2d586e5d1a72194ce2798d4f07c873d52ea441cabe5040ff682664d618b98d4e",
-    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "65954bc862cd149cae2702f25b186fa2166d80cb45bfe6867d075381f2614464",
-    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "f3a5f8318efee7eb9ba4d861876b0a5415f308c9dc2cea751a10b2e259303627",
-    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "d4be89140f0bd4ef9f73a1b54f949973ce560c4dd62c664974f82278ca0d6079",
-    "dist/2022-11-01/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "5b381b513c27f95f9d170e9c532839a27facfe6eb4dd215c078b44fde40e3ba3",
-    "dist/2022-11-01/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ffdf714a07408901962c861103b062adf334e0febc1abfa8c538c40b0070793e",
-    "dist/2022-11-01/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ada55533236ef8c629ca72f929bb87db4b68f8c3d4c6fb3e7001f892a84a2b82",
-    "dist/2022-11-01/rustc-beta-i686-pc-windows-gnu.tar.gz": "b7e059973b61a4d7a0c96b4642629bf72668380a5ad8a2962181b1229ac2174c",
-    "dist/2022-11-01/rustc-beta-i686-pc-windows-gnu.tar.xz": "9aa3bc05e1782b8ff5d278f5b5baac4b0ae523ad8bba2bacd46e1bca11cd38b9",
-    "dist/2022-11-01/rustc-beta-i686-pc-windows-msvc.tar.gz": "acab77f5641be0d7102e6b911f134aa36b6fcad5ac594100889ed0e494eccca3",
-    "dist/2022-11-01/rustc-beta-i686-pc-windows-msvc.tar.xz": "e9af106c009e5fa0da36450a7a89a148ec176bd672ff636010846ab978804e4a",
-    "dist/2022-11-01/rustc-beta-i686-unknown-linux-gnu.tar.gz": "546e7b52f7f9e8c9a99163265dbc8a5ce65dac0fef4f6e1dc8b1bed79f0a24c3",
-    "dist/2022-11-01/rustc-beta-i686-unknown-linux-gnu.tar.xz": "b5ea7fc6016a4abcae3337261724ca2bd21025856134e1c2a1a1922d12ec19a8",
-    "dist/2022-11-01/rustc-beta-mips-unknown-linux-gnu.tar.gz": "0f3e0c8e7883dc7ebbec38e1f3446a33651ebba9a725443856b09ae7e8bcfec0",
-    "dist/2022-11-01/rustc-beta-mips-unknown-linux-gnu.tar.xz": "42871f7f098008f61f6cfd3cf78240156280cc7f5e52860d8125e22b3733a207",
-    "dist/2022-11-01/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "ded0d4da36a0658d46c6705c04fa40d0894b6e113776d2ef8e954e9675e98f9a",
-    "dist/2022-11-01/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2f9ec1ba69a7abbe4efbc5fa00715f520b4c69792b96e98ed8a72e3f798eb137",
-    "dist/2022-11-01/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "090431409021fa0167576c717cf5daac750f9baf7badc3bc031547dad8dedb18",
-    "dist/2022-11-01/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "0542d0336c8cdacf8a830d2a7c3218b76a00ae37db23fb2f12b928bb7b7dd488",
-    "dist/2022-11-01/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "2d6db76bc5242af8c2199c5e74f152bbd8103477855379e7c5c200b498ccf901",
-    "dist/2022-11-01/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "0dc803a305497cc905f3937691e4f1679c72a385b57ee931b19ac5347052c502",
-    "dist/2022-11-01/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "809f547fb5c27c7d15816642839f9ff5fee20f03a3ce390d5b2bfdc983a7c7e2",
-    "dist/2022-11-01/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bd8403226676b78b40c7a494b3a89f9bed956e7eedf3a65a61cba41a6382f5b6",
-    "dist/2022-11-01/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "12cd357dc72d67911a521dc0ea44a8d05bc4c214a7f6b9e88872ddc03811dc15",
-    "dist/2022-11-01/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "d92f790cabb85373455b5adee9e692dc934dff60eccb70c077f29cde35e7cd00",
-    "dist/2022-11-01/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a175a2b7d948459c12f44592c1ee5c79825a120557ff0c488fb0bd4e45c7ee99",
-    "dist/2022-11-01/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d047a4ed562cc91469785fed44d97061d60e1f9c677b5de05245648373df111f",
-    "dist/2022-11-01/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "1b1f20032337e6a0b5e4745a3542a5638747bf2f3b62b2eb855c0ea1ac54d81c",
-    "dist/2022-11-01/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c8a46c9c002ce19e940a449a4787055b4ad45076a606bd68626a1c8d892d8191",
-    "dist/2022-11-01/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "547c670fd6a5f38f98e7b47daaf6822fd5a1abd5a7c11b6f2b5838cb145c615e",
-    "dist/2022-11-01/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "16a0783135c22b64541cbf9201e5f84ab4befbc9ec0117f3e9639cd42dcb81bf",
-    "dist/2022-11-01/rustc-beta-x86_64-apple-darwin.tar.gz": "3121d060a0306c539334fb42c0c6edb6295eb4b5d05b63e55df98d5dc1cb0eba",
-    "dist/2022-11-01/rustc-beta-x86_64-apple-darwin.tar.xz": "4697febb60fdecb5cd70bde0cffad77cdcf8cce057349b4e1f26e3dd4f2f4a51",
-    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "c33bb5e98d83f0a7393c631b6b53eb4a8517bdbf506e1ceb6f0bdd8493fa24b9",
-    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "167e1ab52c4478e6aa8b2bea563f2d8caf3605158731a892181f9d24b027ffff",
-    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "efbe536d85810f2edb6bb7232617f12d3f208e077d177c24f507ff02c8e83a11",
-    "dist/2022-11-01/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "b6acaa3206a3af7fe0e97d4d9211fc76ba972afcdd188443a72027dd34236658",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-freebsd.tar.gz": "8eb739094411afb56ad791b84aa2ddcd2c98b6ca5a4c1cd7fa631571702f1d67",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-freebsd.tar.xz": "4572c19bf416c188a3691cc9542422b92a124594bdf83c82213d07a3aaeef465",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-illumos.tar.gz": "eca080758173b3bee5a1ed7d04473a8334422fc58c762031877e690a255202c8",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-illumos.tar.xz": "68b1ced7efbd6bb4cac647e7417b2ad982f58a1cc546b9391213e85e5852ce6c",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "3a4870b33c0f223dc295fcf3f1c4e331a2631dbc07279f4ca7452d86c5f6e730",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "556821823576a5c0387f0dc89139d3cddc2a17072199607c352fe4b190b7f02f",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "4e1723c8f268eecc9bf3efb16241ce03bf109b9f7c6f4f62e430b7ccd1c092cb",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "47bb3fb8f8529f19fa9725a43a57abd8bc3c7b2a30e17f86b137df0c57a3c549",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-netbsd.tar.gz": "530c24d950028d0745110672fad230da8a2a0e4cd4e5ac5afcf1ff8562288925",
-    "dist/2022-11-01/rustc-beta-x86_64-unknown-netbsd.tar.xz": "cd3654b33b3a8e7fbcde2e380bf2914cb07fe6f8355c8810a5bcfe3a05d63f84",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "47527c62b813c0612b80c864b3720b7e0673eb2dd762887254fd6a80f11c94b0",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "82248dd276ecc0fd45031ba131cb2c870a4b3c09b822d8ad4454f26f506d7810",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "fdc9cc842850023e7c22ac22173a18aa5383a2e2fecb713c802e59d55cc5232d",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "10ddbe6a89cadde47f6f52ef0c4f9ab08f4ced2281fadd1ecbc6a0e4736c9787",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "2135c6d129fa7ecd831e451e173c38677ea39975a91cd6092252e4c0bd93eeaa",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "387d43021bd0ec1586155d1b977470646a68e2625fc192331b76180755687d37",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "41da916cbac667f5f238c3aee3bfb230c3345a4d625779c1fcf57813c9138696",
-    "dist/2022-11-01/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "f28cf712bc617f1755e78a7a442633a7aff78857b98d9aae473effc5684ce8aa",
-    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "065fd7fdcb9f38a9c08b256b46627c8ce38a6433dc162034a306f4d4f4627a31",
-    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "1fc14261867b540e6d014cc5a21c557d0a4bb31d2619ae98a330585915365614",
-    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "1a9ebea072c333e99a3339a87ac3971deb4fe2baca9bd0e8429321a81cce847f",
-    "dist/2022-11-01/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "1c7a72cf8e9cda52d02bd5f4244164aea829914087501cb0bedd75f05f464a91",
-    "dist/2022-11-01/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "1f8405178138601f65dbe10f93d326c705ea91f9e7200f253d6123f618d09ad8",
-    "dist/2022-11-01/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "00365767eb739ecd82c6264795768baba07a101aacec59e137a7495afd0b3288",
-    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "b2e4c4672f440e1f97913497ee158280cb8ed70c81cb47a85e5382cb3de0b03c",
-    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "01bea91a3ab8203b32cbd1fb2945a1eca68179e8f4011e387a230587fc2736a4",
-    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "2d0db2a9f187d300c183cfe2ac6778547ab6492720c0e9df3e78f5b06004e758",
-    "dist/2022-11-01/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b89b02b9fdedb9a93dee602dd9c818e97c397ef73c3f1d0164ddd2ab809cddc2",
-    "dist/2022-11-01/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "4498a8e6d0ae7a793a9f3c84e3bbe9218c37053a1f3dd6a0b4ad7edd1a41493f",
-    "dist/2022-11-01/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "27041aa61921b767be6670f0f08aad1a1ab8d09d0e86cd2e431e54744ed25d0b",
-    "dist/2022-11-01/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "870923556049bd4be8da03fa6d876fa8249e4acf0ea2c83850c4e23a09fe577f",
-    "dist/2022-11-01/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "8c05e1f60a59064c05db7522245d482b559ae858a5c9c772db81a05daa60a4c6",
-    "dist/2022-11-01/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "1a88c20701cc6f7dd2b3e32bef72a78936c39095a35237fc4a4b5a497790a048",
-    "dist/2022-11-01/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "9b5ccf5413650144a79f382efd12204aeddf3421ea6f06615afc489cdf30691e",
-    "dist/2022-11-01/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "4bcf264ba7ce42aee79d76ba0f19818aff71ee666ac4ac417c2a60b0dafa8865",
-    "dist/2022-11-01/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "fd6ff248063cd53ee6b0538c8b3c8af1758ae5c42cc2f5fc805ab96799033f7d",
-    "dist/2022-11-01/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "a03cf4d831ba58d1e562d6fd48dd7558d9034046ae7050883eb1d0fc2cad6895",
-    "dist/2022-11-01/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "30be7166fa091929d1a4b5eed4b72c4b5c94898861f4e91fb45a2b9ad4333ca6",
-    "dist/2022-11-01/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "59f3910a559994863f1910ffcf34cae348d0c07128d00ce5ac085bbca349f7f5",
-    "dist/2022-11-01/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "817df1ddab344e47df34c73918c5bbb3a7b33048f8ac5c5794cb35624f5bce24",
-    "dist/2022-11-01/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7825a5f19cb29245de96eb22183fbfc38b75eda0ba63d2255fa062f9c6764bbf",
-    "dist/2022-11-01/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "0d6384aa1162d821edb6d22326b0a1d481e6735d4343a70df7bead694bb71567",
-    "dist/2022-11-01/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "aef195c86920cfecafc29f80ce6a88c704f09d72011ad1fd462564bf858c75a6",
-    "dist/2022-11-01/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "da43e621a113d88f7c4805f70cb5208bac66f97c68485a60f95cf11f5ae0f55c",
-    "dist/2022-11-01/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2603b5061d059655e3298df94875fa4876d5ea9af1e04dd197ec5cefa3e1eb4c",
-    "dist/2022-11-01/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "f79606c20ce3bf64a9ede63e878cda199e7f1b0b13f40bd51d7108b3d4c72cb0",
-    "dist/2022-11-01/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "f6c46ffbb38f8838c496e1eddea7d6f27392699abfafd0d13b234eee39238181",
-    "dist/2022-11-01/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "9244fc29cd3c32c971f44fcdaa26623b8976efaf0a4705b573798af5b0b0896e",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "bd502f9105d56af252da1038687a4e942a477c7047cac9730de7414cdbbfbc48",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "426785558da44683a554c542475c9402932c72d63148c37917e8cc6e429ad413",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "52646c86ad464c5803f74ab37166dc1692383bc5fd94818bd579e518c327251e",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "67d1490a41932c2a89981e18c9735d4437faedd1e708e26f75dfd21d4709488b",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "9feb7b704a6d3e6b019a99ecd033042ce81a4b126e4288e0b4772266c6e0a65e",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "fba240009d3f27e04200133120c46112ac64281e99952da44d6fe8a01557f236",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "ce15bda4992ada52f94dae6b1a0e220f26324acefb62094035abe112aa878fec",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "189a8579cf3fe99b9c084821ce1ee9bec6977470341e2ae45b859dcdacf65d21",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "15abcd9e43f2c87fc894b3e280a99865508f9079badcbe7be07c6b79e85f01b4",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "f52dab31a428e568518b00d3afc1426569810bcd20a7db1c0093200c6db86d24",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "57ec35b95a5fd803b2d4dacf7657847111a6cc9bda3cda962174965cd6005085",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "96987349e20e3f602bb6f518924660c09a4575887730b1bbe36adee921921956",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "76d6f5882573169985f5b8a9e13cee8bbe3bd3b423ad287280a0809c6a5efc5a",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "9a2c79685b4ac57efea65e43dafa28b59cead1c14e98f10e0196cb2cfd2fa0b6",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "0be98b45af7e666955e6e0adb5b4cc3f5517c8d144702b10daedd053450cd5d5",
-    "dist/2022-11-01/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "ae9ac6e1c0e14bfba746f3a85bfa3f009113d0edbf880a2cf20ece6046ee27bb"
+    "dist/2022-12-27/cargo-beta-aarch64-apple-darwin.tar.gz": "00b7df89de07931d150940536a1e6c980897ed0e9880bb6f24d5ebbad896c8f2",
+    "dist/2022-12-27/cargo-beta-aarch64-apple-darwin.tar.xz": "17e1e9cf2c4dad4fec7f420f43cea21923d76ba2d6f87ad67c90ea9c8e4a04f6",
+    "dist/2022-12-27/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "783b7e2569490dffc953d4b24e659fec384739ceb8bad37e3a97df374945a91d",
+    "dist/2022-12-27/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "a9402480620b03c010cb18dacca9a95c82e7b6078d2c1163543bc4292d7dd300",
+    "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "7fa9aa92c2b1268420f60af2826dffa50b61c9926a2a1cd1c8273fe5861cde11",
+    "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "97d583ed82db1fd5a03ce44a660f1163d0812b6f352adc6d78e61d7ae4fbfe23",
+    "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "69236898b091d6ef31445eb1223acfc01adf21fb1aa277a7d441eaa300c0c9ad",
+    "dist/2022-12-27/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "4a92788cdba1705b79ce9999d45a62d4631dbc59cc980437e1635dc908458b66",
+    "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "b35b72b16c59b38e38acddf2c06c2c819ca78f146bbf4f3ce9d7ff982b86655e",
+    "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "81d7fbe3f50cbad04c2ad0e118001976a880d23ad2a894ee49c6f6c10583d10d",
+    "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "942f6860e2cf9da7c5399d308acad43f862750bf7d383444c2dd636b86553e14",
+    "dist/2022-12-27/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "5f2f3c7186a2cb28f96bba8db7d404b0f3338bbe57edd631bb16fe4d2c8d493a",
+    "dist/2022-12-27/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "f15932518f114587c3639ed270cab3e4ef4eb28e0abb6b59b5f63138fa43e829",
+    "dist/2022-12-27/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "41116748ab087e0c7a5354508fb95e1a966212ef5cac40da59e363108077c3a9",
+    "dist/2022-12-27/cargo-beta-i686-pc-windows-gnu.tar.gz": "37bbf0a9dcc1b3fbc11a5f72de922fb0f5dc80a632d803fa0a892d72bdd457c1",
+    "dist/2022-12-27/cargo-beta-i686-pc-windows-gnu.tar.xz": "7a8afd8a69e1e25e47122096920217bbe765e82e831583420487702831241d5c",
+    "dist/2022-12-27/cargo-beta-i686-pc-windows-msvc.tar.gz": "c40ec16780156f6568bf8f1353a3bb367d4bec09dc6e98b03de44bd2ed301ae8",
+    "dist/2022-12-27/cargo-beta-i686-pc-windows-msvc.tar.xz": "94320949f071236d828fb1252159f0f2b1f18030303af1ae0b7ca06cd9567de0",
+    "dist/2022-12-27/cargo-beta-i686-unknown-linux-gnu.tar.gz": "1fb3fc33289ae716f950feca832196bb32cde0556e41e501d05c84116836d916",
+    "dist/2022-12-27/cargo-beta-i686-unknown-linux-gnu.tar.xz": "4f112ea5a91abbf63db484368090fdf8fbc6b7abc1a5d7c8353df15e7908c2e3",
+    "dist/2022-12-27/cargo-beta-mips-unknown-linux-gnu.tar.gz": "b90f3c17c73f4dd7b36e0ff56b17be8e1c90f82b33c9be28b7b813fc5c788e05",
+    "dist/2022-12-27/cargo-beta-mips-unknown-linux-gnu.tar.xz": "8754bb3f116b09a8b38ac0684014532a19ccb57e4e94d1097a8484e8d67e31ce",
+    "dist/2022-12-27/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "549733dbbc3ec23976d6975e78ec8b8a30396eb45e4a8f5eef6d4c846cf04da1",
+    "dist/2022-12-27/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "f5997ebe7c67969b7d14a2233897b6014ebd9b38010eee101d9e484d42b220c9",
+    "dist/2022-12-27/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "3450c71c082bf84115fb035239453e39230afa0575dca0fc52586222b474a0c2",
+    "dist/2022-12-27/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "a16c397c5e980a926e0122cff5f8d30c4b54c2dba7f48ef00b587c5cda8f500d",
+    "dist/2022-12-27/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "62e025463eca2dac0547275c7827e6ecd109d1b84d056526e647abd220b3e1fc",
+    "dist/2022-12-27/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "99c5f5511b23d93707df394c2ab90ddd98e7876c9ee74c861dc919cdd498399b",
+    "dist/2022-12-27/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "eee574420f365d02d52f5f4754563bc1fe4f0b07d02a554f6aa886bccbe4c092",
+    "dist/2022-12-27/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "64e53a591e2d4dee9935fca4a2df18fbbed1b00b74dd6631473ba2d5b257891b",
+    "dist/2022-12-27/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "37d2a5f1c496c8ad8d2b5af5e89a4a325ddcef32ebd7087ef3cc9e653e5a8f4a",
+    "dist/2022-12-27/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "8753d9bfdda6decdcc4f58d2391956609e0aeb75ce4368c7ed52c23ed3f28943",
+    "dist/2022-12-27/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "303c63a294f2112fceb70cee063f35cbee3296b93ca91e43300e72b064d80da7",
+    "dist/2022-12-27/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "96b752dd307d2709dbf2b91c687a55992f4e0e5a143223a8c2a267883b4a2832",
+    "dist/2022-12-27/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "e5c279922e9adb47e6ecaee191ad291bfc627aa05e4c026628664bc47e5ce254",
+    "dist/2022-12-27/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "7e0145fe22bfca7070dcace196e3229a86f9f5b31ab1cfc4fd7ff158db5b1388",
+    "dist/2022-12-27/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "49df0b5774471ced53703942c6551c045ed56c92a3a224615f583511bc845a61",
+    "dist/2022-12-27/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "955e67ac19fc7a2a882f759339343c466da9658b2cd95799dd78328c13d6527e",
+    "dist/2022-12-27/cargo-beta-x86_64-apple-darwin.tar.gz": "a0e01a9ded551ea1f411da70d4481627579e870c2ff7592efde1d8be83ca46d5",
+    "dist/2022-12-27/cargo-beta-x86_64-apple-darwin.tar.xz": "a9205d81dff07cbf2468fa6f6999fd0f1266ad4faf84f5688e3e5cb330bdce0f",
+    "dist/2022-12-27/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "d6406b59361cdc97df606901beeafe6660a4cf557b9de4a313d4659c83f10255",
+    "dist/2022-12-27/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "ae15fd38cfcd149de306280a48785fe269ea36b1a958de6815adc7a80792d798",
+    "dist/2022-12-27/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "d75a793188af608b8bbd92907ff69294bc66b85b7ffe03882abcb661fd8c27f9",
+    "dist/2022-12-27/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "26f4ed51fc227dccc67d4c68fcac78374fb1441093d3524ec157b1b6b6e90012",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-freebsd.tar.gz": "6503b65a5258b5517c5213f0fb858aeff7e00c453a3633749d1a72f7f645050b",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-freebsd.tar.xz": "75ba61fe1670d0e4cf9f9f35460c663701c75ceca95917ed25e98f20cc2f0ef5",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-illumos.tar.gz": "e003c3a1ed8b57546e6ecdcbbcb58a97896a8e511b6a8fdc31100c24b8dd5a17",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-illumos.tar.xz": "b377d76b8fae7ebc607f33400cc0b37974fbf02a4d29187b1f0f6f668c12ff01",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "0dcfb9c65b5ad5c6af905c78d6914f5d7f8a62def817e64192b29c957b848783",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "1ca64be7777194c3191350723e8a909cce93d8ac28ceafb5df641f3066c6a8b9",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "9c24ff865929e88db27285fcb4a10adf97289a388f93ff5fa421211f35267047",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "b794e0397ca0ec274e307468ed56b8116438c0b8a444f593eb56350d687e8137",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0fc5f8716933c46509cc05492e5bf75f6d06575dd6f803882397929b95394e12",
+    "dist/2022-12-27/cargo-beta-x86_64-unknown-netbsd.tar.xz": "0cfe7415cb4c0a96019eefe0363c1d61934d76f3b5fb72a113b9de1401ecfad9",
+    "dist/2022-12-27/rust-std-beta-aarch64-apple-darwin.tar.gz": "777b016bebe68ea79bfb336eedb595174466bfd54321523b9913f5c2741d0135",
+    "dist/2022-12-27/rust-std-beta-aarch64-apple-darwin.tar.xz": "c4ab94494052bf3fb37a226e1313886546bde1ec4d7188049cb95dbf2963e1fa",
+    "dist/2022-12-27/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "884004f47fea38414ed805abda4afce3adf5a83fcd072ddececfa888e55bdef4",
+    "dist/2022-12-27/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "db0858bd63fa8609ceb6ee42cbddc31f31b2a0ce0c02e1fe1c2d32f0c8d607c6",
+    "dist/2022-12-27/rust-std-beta-aarch64-apple-ios.tar.gz": "996c8612a39bddb3047ce0f23f761deeca61d15b36f2ea270f5a220d14c1ed27",
+    "dist/2022-12-27/rust-std-beta-aarch64-apple-ios.tar.xz": "c06360094800d069261d363b709ca552d3899d50c12d39c23eb58d75015c980a",
+    "dist/2022-12-27/rust-std-beta-aarch64-fuchsia.tar.gz": "891f1909fcc78019f77d704c3b3b1031c605dee01a116f04e7f4f402d6b9b2af",
+    "dist/2022-12-27/rust-std-beta-aarch64-fuchsia.tar.xz": "3033d409735b299b6754852c28c1dac378a94ad892144ed76199d542a265c8a7",
+    "dist/2022-12-27/rust-std-beta-aarch64-linux-android.tar.gz": "080c97ad158327dfdd24a3c17477614de1dfe27f1236c73ed43b1e7e881f6b06",
+    "dist/2022-12-27/rust-std-beta-aarch64-linux-android.tar.xz": "80b89416148f4ed917978686ba337ebdbb3d4a50903a792831fa3b83032c43cb",
+    "dist/2022-12-27/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "854badcf35650c196b2051be46254d2f4e86b4522dbfa9f1d1a64148cae7bf1e",
+    "dist/2022-12-27/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e4ccf358da4cb13b281c999318816fc99948a3531e9ecd6d0abad9b819c117be",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "9473f12fc35106ab9144b38bddc3c35d56b0413bec06c2d1d5f43d4fde614331",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "5cb44be7d8adc0589afca90ef0669c42f03a61a622d856fb057d450554d24c01",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "25ebf045fc59488abc07ed24aa3364fb64cc186f6c852b12cb5c094f81d5fd69",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "d43bca65f55159d6eafb7e342ec5d4598d63bc8fad0c9fc15b6bd88743321d4e",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "91198741990d9300024da5113843cbeff02ed9ea344d9feb57736e9334136d27",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "0aee6204d34246480be1d0f6efd6a66eb10d83a9dd1c215433e840949687c598",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-none.tar.gz": "97f3193bfde82b997346b49231a0f24a6960da88773bf27c73f57f40ec4f84e6",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-none.tar.xz": "1d2122442cc0a6595c901831e8cbaaeafd2043fbc8c4b028265310d2086673cb",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-uefi.tar.gz": "6d351f35cb9252c2825311eb22049283534cc2877cfd673fc1b5b3c94c6ef864",
+    "dist/2022-12-27/rust-std-beta-aarch64-unknown-uefi.tar.xz": "054bb5a98df25830201ab04e81f63630dc329f48daa0d715a3443f95d2c0f442",
+    "dist/2022-12-27/rust-std-beta-arm-linux-androideabi.tar.gz": "93b70e7c6b686ed5695bcf2f0b2da14e89a50e54304d445ebfc35107f689c442",
+    "dist/2022-12-27/rust-std-beta-arm-linux-androideabi.tar.xz": "9b8983be6089216428007e968844f57bd88e2371dd592b1ca06aed2aa6479d8c",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "753ef462dd47349fee5f45adadc073363250fbcbf566ff337250466d0ce73343",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "c19389db997fd0e158e5a5e847f566f6b03f06b3161ce5644ca0178fae25d0f5",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "c819d6a3de743f54e28eab0f2c7744dd5a5be7c6677bb712bfd3f93938435194",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4ca09f9df5476449c3510c82e284026329411253e2a02c90e6239f30a9a6074a",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "f7994d565baee0fbdb010211fcd30398f7f90bd97770ce72e5ba34bf1f06a466",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "f54e1efdb9a088a13371e5fd7e1599a7bcadc5db4247e8811ab9d374c17fac8a",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "add3333e892ccfc31b8fa506e79d5633261daf13e7902549ac5ecfe8f3655bbd",
+    "dist/2022-12-27/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "bfa9a7cb0de16ecef093d593677e32164e4e68042806f543824c16f2a12b55ae",
+    "dist/2022-12-27/rust-std-beta-armebv7r-none-eabi.tar.gz": "81c958b4ba5933c02cb2872efc4d5de86a2bc1a1d326bf563256ec74e256fd8f",
+    "dist/2022-12-27/rust-std-beta-armebv7r-none-eabi.tar.xz": "634d2e35b2314826198eb2a7fd6f253cac5c2bbe7a5a7c7cdecc09949db23b3a",
+    "dist/2022-12-27/rust-std-beta-armebv7r-none-eabihf.tar.gz": "62dd020647cfa88c6719b4b9a803d07f3ccae7c2f94c924e1529def264db1be8",
+    "dist/2022-12-27/rust-std-beta-armebv7r-none-eabihf.tar.xz": "53a03694b610146cb80e0ef0033600ea4dd6f8b7d413c3ac675cb57c9b4c5cde",
+    "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ac7c396d35406501eda50191b92abab74e19148ec6caa2d5171bba35f2d3ec96",
+    "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "058c514636a2063193d278e16fc683dbe9c1dadcbca45707152d150dba71065a",
+    "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "bc5400e734bc4747b3ea44bb5c3cf9af5f11d5b5f2e970bd4626a25a276f15f7",
+    "dist/2022-12-27/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "0079d1cb3d1fd5be99bed480e6ec0b451dd9e2a2299e3347cbee33344cd8c718",
+    "dist/2022-12-27/rust-std-beta-armv7-linux-androideabi.tar.gz": "9dbc9e97f9990f03efe67c817c9dda7fcdc931c7605742182f4d128859c1a53f",
+    "dist/2022-12-27/rust-std-beta-armv7-linux-androideabi.tar.xz": "d0119bed6cb41629aa65d83f7c1021e05e2f90bd21a28e6f0d3b6f0ea9127dd4",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "09cab74e4a6e38d07622fd80e97d424d7437d554c05ce1896acaaddad0e3b637",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "4602ca768e8ba85cfc5a4d4a2964cccd048ad82f349b7453f077e38de918cb0d",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "b983a7699fce4c6f9c7f16ea3fd2905a8ddf21623bae71a9e7515b5cd5b288ec",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ca2d6d4c09326559a1528cf32c7a899f985c7e3b7751cec8911d0facac149e51",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "dfa375f608f297f4dd0fc39921609ecebb31101850d73a8bb8b67ce98e319f3d",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "3159afaebb2b17f6b12128e2829944f9406e26cc7019eb33839fda311ea0b809",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "5a2c2361c944d85455b7a037bc820fbfe824180106f5a6d6fbf4066ef78236a3",
+    "dist/2022-12-27/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0bd7ac1cada0a3a3894d404ad5871ef3abc4963eeb5a1f05f59e6264b1e6cc3c",
+    "dist/2022-12-27/rust-std-beta-armv7a-none-eabi.tar.gz": "1f9daa0af4695c51e4cda38235497923b9adfefd1a6eb4be086d720cffab7594",
+    "dist/2022-12-27/rust-std-beta-armv7a-none-eabi.tar.xz": "b9e5b75720d71bc9e0e16b73b7cf04cd3e5a57da7a6b842926ffcf273308543b",
+    "dist/2022-12-27/rust-std-beta-armv7r-none-eabi.tar.gz": "4837b13f144f12e9edb5b49ddf5169d1cd13cff0a3ec3e54160714d45138448e",
+    "dist/2022-12-27/rust-std-beta-armv7r-none-eabi.tar.xz": "32a56e92757a9ee82ff71962c7c8144e4240133d44de77d5955510640a31061b",
+    "dist/2022-12-27/rust-std-beta-armv7r-none-eabihf.tar.gz": "d31ed0250a195a8043e71c8ae3b2e86111ec07b00892ae05c3783761b20774ee",
+    "dist/2022-12-27/rust-std-beta-armv7r-none-eabihf.tar.xz": "06b70c26d9161b17c2e4ca9255ae1a73f7bbeadb24d733c320875e3dbbc77caf",
+    "dist/2022-12-27/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "6271afcf4b05fb4de2ed08ba441b3ee0b476e2e33dbda8a5efa3d7540475bca5",
+    "dist/2022-12-27/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "131c51bb571df676dbafd84d5015888c4bc15130bd7300d4c53c1667907f7f51",
+    "dist/2022-12-27/rust-std-beta-i586-pc-windows-msvc.tar.gz": "d6bca2e8ba737a4704dc01dd6fca58a7c8dc8a065107f9fa98588c5fbdfe39a3",
+    "dist/2022-12-27/rust-std-beta-i586-pc-windows-msvc.tar.xz": "d64aa029d4209256e18d7bed6e0e28156a965b1d50cb3eb8d70abab57be55a97",
+    "dist/2022-12-27/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "f48248f5fedc961ea4050254cf9bdbbe70420ebdaf712847a5374a3c97e21df3",
+    "dist/2022-12-27/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "c9287bc9be332f084a2779803964ae374930d3bec787155ac3c8d1d6be6a587d",
+    "dist/2022-12-27/rust-std-beta-i586-unknown-linux-musl.tar.gz": "1914ba0edb77b0bc7cd83dd93d8a6ca53b29800844cdec9a976342982aad8b27",
+    "dist/2022-12-27/rust-std-beta-i586-unknown-linux-musl.tar.xz": "30d5d1bf54eb6758e0bd3a3f48f186a957fdb1310ba8b3625b5f33994c8a58fb",
+    "dist/2022-12-27/rust-std-beta-i686-linux-android.tar.gz": "6c05a59ff653bcde6a71dfcbd38718ca3cfeb89b7ec09d1cd380fdb589941d27",
+    "dist/2022-12-27/rust-std-beta-i686-linux-android.tar.xz": "80b6b57ff73a9483046380c0d4cfc8c090fca5fc4174d5c47f71fffccb7178a6",
+    "dist/2022-12-27/rust-std-beta-i686-pc-windows-gnu.tar.gz": "941bb6f5107630a0b26b8749be29c6df920ccb467df367a5f55491b062352f4a",
+    "dist/2022-12-27/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f3f2ece3bb0080980e099c176a8a1366171741450fa8b8e515362572b519e19f",
+    "dist/2022-12-27/rust-std-beta-i686-pc-windows-msvc.tar.gz": "a94fcee79bd5941e718a112d855163563f6e5377b59a9c1405ac8804131b0383",
+    "dist/2022-12-27/rust-std-beta-i686-pc-windows-msvc.tar.xz": "4bea862e2d998e976526cb741b7d674a7d620fc7e4838955ef4c53d000cf24aa",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-freebsd.tar.gz": "e5cc60f1c00d966809cd76fd452bbb03452c5cc94a487ef4ad14af12608ae5fa",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-freebsd.tar.xz": "df8df7d1750cf9e92b3e4b57b83b195c1eea6ca62f38ad317882a69e2e813ba9",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "4ff8fc04b63f7a80587d4f75376c74ade7721369ad1508faf5c0f83930e1cf7a",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4716141a8be8017adb8540c05f88e6463b2add95439320b0084ffb290bc0d943",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-linux-musl.tar.gz": "d7cff128c80db94aaaa2bb708bafa3f857fe8b819ff21a85f7c6c7c5170576be",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-linux-musl.tar.xz": "bc83b17627e87ee4b555e9cc5912dbfbba74586f46719994be6832e22f70424b",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-uefi.tar.gz": "ec6723c138565c4d9ca87bcda199aceb7b3a42ddf979658cf9e8433a4dae9c70",
+    "dist/2022-12-27/rust-std-beta-i686-unknown-uefi.tar.xz": "0e67f10a29f2826399604839a4dcbd173f8de39a755283a0c245c54b8a658210",
+    "dist/2022-12-27/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "a78f899f6fae1671e41aa7d76b37d9041cc32dfa6e9315dabff3afe21f93700b",
+    "dist/2022-12-27/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4c74cece45b9271c77c4b328d1b3d876b50429077074580d771fc2b03f0d4738",
+    "dist/2022-12-27/rust-std-beta-mips-unknown-linux-musl.tar.gz": "a854fbab503a0541d593cf9496a4e4cf8b9edb49422406b3a7f34e3fa21905f6",
+    "dist/2022-12-27/rust-std-beta-mips-unknown-linux-musl.tar.xz": "f42a81564e7366d5d630632af3113b99c5de6d147d7eb9e31da762bb9d35d4ea",
+    "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "de070d1ae3fb8a825092a9a78c26db553839c6d862e451a497d5f94230414bc5",
+    "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0a7092c99c587ef69801af713ef834bae809e4868dfcff43babd44bec532717e",
+    "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "7077c20142082b0e2b8d6299ffcd8739c8295d315b917563cffe6d42e129cd08",
+    "dist/2022-12-27/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "86f0988f3baf0b5bbed81483e7d68004651f227ab22d1d36b34c73f132191dfb",
+    "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "536fe3059a8095bcc1c44391c27b7d9832d6a057388b4de089915810cbe1baae",
+    "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "6b4e397a3a175f4cbbddabb750df14d668c1f4c8520577d35fbcb9dfa8613097",
+    "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "30f42499ab4f21caf21551e0e92bb5db9a2e0f42fd0b3e59ee9789dd40d10391",
+    "dist/2022-12-27/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "1190cfa1023a8d35d202979a1070863bb713495c2c9b720d0371b6d70d23bd7c",
+    "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "4ac79a395ba5d70e1a09d0e1ce232b9405b9995f7c459d176be52eade40bbab7",
+    "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "42f3666885680cbb2d15ec85cfbc9103e5b170346a9b8cff63a2d15f78472c67",
+    "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0b1c979205f8476ad6f0e35c05acb1976cb4c44006c25931e73c35025939f1ff",
+    "dist/2022-12-27/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "7b6c76ae46ca56746b0bdea404125256636f05c1354e5dcf32c2a487d25e0ee1",
+    "dist/2022-12-27/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "ad9cb2ec325e2a2f14ac4db6a5df53a7c06adfe8c4c58f0f2c83748a34d0c550",
+    "dist/2022-12-27/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "1d507bb0cd8c80ee4e9155a0740c2319027ee5280552c1056ee7921a82bb9aa7",
+    "dist/2022-12-27/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "e8d3b7bb483d7b3b737840ddf7a27a28c216d9d0b3ffc7ccded547f76bc932c5",
+    "dist/2022-12-27/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "130edffa27b82def2876fb5562fc7a3971d33855e3ce023e18507b3e1bd47d10",
+    "dist/2022-12-27/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "b5659dcc18fb0e5849acb13df7153518c8df5ca9566852cabaeee33583321d1f",
+    "dist/2022-12-27/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "6bdfae3e9cf07608c862f4c042c47ed318c388bfcfb4cabfa233580b90c7a459",
+    "dist/2022-12-27/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f28795f8c2823bd817df63486d8a11b6b7cfb9538110e87d8d008ed979a81a3c",
+    "dist/2022-12-27/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "695f6acb6ddb4c4a87515646157b88d2f58e2114b100f22bedcd4e2fa8de00b8",
+    "dist/2022-12-27/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "5f004e4b265efae872e8b0d8fda81f4e65cc50452d558ef90b9bef7639f6ba6d",
+    "dist/2022-12-27/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "c93c1cb534e83d43c40c62ed6623559e3e380f177c4bd151a0d1389a80a58139",
+    "dist/2022-12-27/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "79988bb7bfa27dcacae0c459143be6a34f328ec6bcb73c2267d41a6f022fc045",
+    "dist/2022-12-27/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "11235a96e7e8e14a173db0be71cd1ce7955c79f5a7d20b7436238256a06342fd",
+    "dist/2022-12-27/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "a315accc791f1247e92a6362eb7bd6ab899c4688db7decb36b8d892c200186b1",
+    "dist/2022-12-27/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "a4f6ac1d21ecda00c9d3e34d900771a4c5a50e3e5071d2eba837c9e4738edc80",
+    "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "06dd8941f63c3031fa0383dd34981c655b26fd10d5510cd06bdcabb4a592a435",
+    "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "882e464b44acb7e286f49d45a4f5a41fbf570ee0d78f1915fd6f94ac392fa928",
+    "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "734d6f54d143ddddc2141da72ee02a32d4d505e20eaf0041c86c89f8ad8730ea",
+    "dist/2022-12-27/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "be32ca1ddb2d48877c70c9a128dba02bfdca7a00e93c114c3c99127e7be04adf",
+    "dist/2022-12-27/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "a6c70d3715b7e50ff15f5473348d8e1c5a061036055a85784b5e84a99e4008ee",
+    "dist/2022-12-27/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "0dbbf637d310f7ef44cb1bc08122c172606c8ff1c886195eebbd52cad5789597",
+    "dist/2022-12-27/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "3e2f7751028f9123d94ff72b08f8ce0b40da36eada77e1414d4178756b46313a",
+    "dist/2022-12-27/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "382a35c79a03f7abebb9c5788f9dd19bd0973cb89e9b07a971eaafc611c3645a",
+    "dist/2022-12-27/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "3eb49f766b206966433eecc7cdbbf709e75991644eae6f44596e5ec893fb3e8b",
+    "dist/2022-12-27/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "9162e50f2ddb12fefecdc7c4c2d60e76874e78fd89b45d7fd81a6c95a856ee28",
+    "dist/2022-12-27/rust-std-beta-sparcv9-sun-solaris.tar.gz": "dbf20b8fd52e1b6a553369a1690344574e6c660996ddd5121d4a05bfb71c87aa",
+    "dist/2022-12-27/rust-std-beta-sparcv9-sun-solaris.tar.xz": "a40d8d444e57eabeecf8acf0b59f24b5d4e2c97ee538bfe38904a1f81a48fb14",
+    "dist/2022-12-27/rust-std-beta-thumbv6m-none-eabi.tar.gz": "1e63244aa865e6a115e603f238b64410606453fb38802b1684fa6397660a1501",
+    "dist/2022-12-27/rust-std-beta-thumbv6m-none-eabi.tar.xz": "ecd94de3f4a3aff8f9f920ff68383e342dc293ad2fb2584c9d9e48bf60eb82d5",
+    "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ad21ab2584999c7c528dcde2e435d0ee73686b9b94c4f31dfeb3abf3cf9b9821",
+    "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9394854e14bc3e671060630c01b6977ab5afcf9022790986c492fe58f0509191",
+    "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "1cbabb457c0546da725a548a88b3268bb0feca4269af2b9cd0b98455c2e0c468",
+    "dist/2022-12-27/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "1bb23d8d2783554e2043ed71cf982d9750bafa3ccac6e387b25d279137042867",
+    "dist/2022-12-27/rust-std-beta-thumbv7m-none-eabi.tar.gz": "076a918e524cc33a02ab2c94e3a607dd293d5d6d63e0797b16f2246057d1082c",
+    "dist/2022-12-27/rust-std-beta-thumbv7m-none-eabi.tar.xz": "de8f3e8907fde91bfcbff0c353eb3d1cb9d06dec31142479ef1ad2c6c368d5c6",
+    "dist/2022-12-27/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "658d66031594324821649058e16e3e0b06542e8c9dd17c5fe705c487b5915ffe",
+    "dist/2022-12-27/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "56a9a0235c0aacf561cfc9e7981c57a4d174dbedf5ed943d266302662246b10e",
+    "dist/2022-12-27/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "3318c23ea42624e26cf2a25dd5fae206ccb96137d6833f28d7bfebe3ba7e327c",
+    "dist/2022-12-27/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "b91396e82a9c30711608c3650d637a3ad56ea90d682460c791210f8bfb5a6854",
+    "dist/2022-12-27/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "55b45e9863e197262bd97a9bcb80991c9c34385acaa228b062546b690621b530",
+    "dist/2022-12-27/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "dc0b7ed56a142475759164713bcdd7c64958c7e7febcafa5371414082ae495b2",
+    "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "b2bed92d03b295035e4bc4e0fd63b44ee1cc634edb394cfbd7afdc00353a73e9",
+    "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "bcce53fd7c0c494ea1c45227190a959e992f07851dd064b2a9c599fafb07077c",
+    "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "d6df9026c218b906671e89e433b165552a9486e41399a8f01a12d10495afc8dc",
+    "dist/2022-12-27/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "f5f2411e3ff94f6e524a14ee46e6e6bc2e9ec91e395b0382f7a40bc6e970d623",
+    "dist/2022-12-27/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "c766ec36907ce0a7e76ba9a227fdd57eae7a744bc5679b67a6ce1d6ab41ea19f",
+    "dist/2022-12-27/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "de5f398bc34fb22489e9f6f2a9847954d8231ff5732f2595e8be93eaf7849986",
+    "dist/2022-12-27/rust-std-beta-wasm32-unknown-unknown.tar.gz": "e3ed4bc39da4731443b3bbd584106444aceaf91720546ac66e98712fe65dfa93",
+    "dist/2022-12-27/rust-std-beta-wasm32-unknown-unknown.tar.xz": "704a65e4f3e1afea9d1bd6a60c4d3e5fd57e3e14ba0dd2e2b94305c3e1c92cb8",
+    "dist/2022-12-27/rust-std-beta-wasm32-wasi.tar.gz": "03e2ca41c758fb4f9a2ea562ac4ed7186e27607458bdd7b575d786368336ea11",
+    "dist/2022-12-27/rust-std-beta-wasm32-wasi.tar.xz": "1ebc2ac44181d6d26928cbd550c64c5b496008e97356c68497f15f8cc8351f37",
+    "dist/2022-12-27/rust-std-beta-x86_64-apple-darwin.tar.gz": "0f0520f7163ef3d659e5761b2f0c7a9f2de00b2f769eeec8d1e7e9b3b08daf6d",
+    "dist/2022-12-27/rust-std-beta-x86_64-apple-darwin.tar.xz": "25795f1876330666b7fd6dd724661b364643448d0688d479f492c02faf2f7a4a",
+    "dist/2022-12-27/rust-std-beta-x86_64-apple-ios.tar.gz": "014a022bbb524d8c550d5dc7d678b9764adcc9962538980e9596ebced9c5614d",
+    "dist/2022-12-27/rust-std-beta-x86_64-apple-ios.tar.xz": "9b38e214e203c959eba0e8d651410f6cafc9e4b5725228c2bb4ac8f562e6cfa7",
+    "dist/2022-12-27/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "afd9236304892945334183b31072b9b9f9b4faef8b7cdc4ad1f45a9b3e080a58",
+    "dist/2022-12-27/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "33a7e5fd18f2166fb2b6cbe7630d80915533d59afc0080f1370bcfad1114eaa1",
+    "dist/2022-12-27/rust-std-beta-x86_64-fuchsia.tar.gz": "7e91e1298da3676c4c051d7f34eec21f2fffa0a34af212c785b79c2d1048fe92",
+    "dist/2022-12-27/rust-std-beta-x86_64-fuchsia.tar.xz": "fff70ed752d0760990f7a90bc3c50ac6586e8b012e61a15b6dfb325dd081b9a9",
+    "dist/2022-12-27/rust-std-beta-x86_64-linux-android.tar.gz": "f9183794392422fbe8cfd61ea7bae0dadd8731e82b1d15a59f4e93acccd2048f",
+    "dist/2022-12-27/rust-std-beta-x86_64-linux-android.tar.xz": "4fce2ab0dacac153de7d9805786b17d517863b0ff04a8224540daee86eff4056",
+    "dist/2022-12-27/rust-std-beta-x86_64-pc-solaris.tar.gz": "d5b64111b3763063c38ae63915ca366a4fdb63f0dcf8121588a8953f01ebc669",
+    "dist/2022-12-27/rust-std-beta-x86_64-pc-solaris.tar.xz": "c396b086773dc06db2e59bcdaff8ffbb7069efee5841b9e3cdd4dfb05fd95ce4",
+    "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "e851812f69bcb2fe606bfbda125fa6b3f55752fd1a2330878c48ca99eedbb8b6",
+    "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "689738a0952a0eab27ba3d3f9bc9b531ec29f338ea373bfa783a83786d5c2885",
+    "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "b51f78199bfc1417f020e2d0dd16044f63f6b6675b2b6856f669f8604e44a6bf",
+    "dist/2022-12-27/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "7713269f3c51717f6231cf4100043eca2330512b602c2962da81af561e90193b",
+    "dist/2022-12-27/rust-std-beta-x86_64-sun-solaris.tar.gz": "9f0a129f4c2ea324e2dc94fad3f7acbc7bf2b988f66d9c42dd8abbc60c569acf",
+    "dist/2022-12-27/rust-std-beta-x86_64-sun-solaris.tar.xz": "6ca71851fd0a7879aa750a63deb4ee587f82c28b27486f716e4fae5ebe599086",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cfbf0f85757854fba1551c3312baac820e398b573d50b005cc3958723db7c82",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "2e2dfb82fa7e23f888ae9541a30d15ba978cb29bbdfec6afb00590a39c16df5d",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-illumos.tar.gz": "92650856a7e74c8b912d5c84cd1002a490f9c8e3fa4506733fcbedb3cd42792b",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-illumos.tar.xz": "3dd302996bd3fb9f8b077e6d5fe3dc6f7dd9590d5fc3eb3bab2cffaada4e99d3",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "3a1faf905ffc7263e725ce7571cb84dd8698adbc45b6902da86350299b2e3ccb",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "daef635cdf88c8d9c924c0d66e2b26db1f56bda9b48ca0c21e089060b07dc997",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "567bb99f67737cca721d1dc6975daefd3dad29b13d531d3b939405ef4e7aee84",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "aa218c4547e77f33ba4bc45bba0b6fcf3cce9355c2cf11d74a3a4c5e49f9b3cd",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "de43b04cccb3c2bdcd2a7993c391299a4bde5041102ce0eb5e32b6cfae86cd79",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "f99963704b4c3189361925ec8b53daa2ca15ae4af9215cbd87cfec23e044cefa",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "3d4949e63f137552e3b74e50b366f95d7a153e7c61cf5587634be51516fdc610",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "5b48095a35f862190536e64eff726327e25c23981c0bc1224c8c44bfccbb705d",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-none.tar.gz": "12b5c69138260daf976e963ba503c66ec4432f11cf7506bc9ba691ac2c1df4a1",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-none.tar.xz": "5c334a67f6586dc406b6e55c7f9d64b7701e1c7879bf5860b378069301c57854",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-redox.tar.gz": "58c15f9119e5f78d7c70b24e67af57ce10bb2d2cb1347b9b4631478665c624de",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-redox.tar.xz": "a2f8b635254d53ec5b902dbeb8ac63c6c3982f94dfbcaec3d093f17f0f5fa896",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-uefi.tar.gz": "1ce5c25480e97699b12c180ed6198766a0c12a3543dd317ba6f4a52538027b0d",
+    "dist/2022-12-27/rust-std-beta-x86_64-unknown-uefi.tar.xz": "e4d9ffe34ba40e5ccf87007085dc4daa20a8a52944f092e2a075527702b55072",
+    "dist/2022-12-27/rustc-beta-aarch64-apple-darwin.tar.gz": "f5c8dadb8eb0335a50326a94f858625e4f01e3159e933d58f9d24338d47943be",
+    "dist/2022-12-27/rustc-beta-aarch64-apple-darwin.tar.xz": "0a6eeb32e4d85b628044c3e075e5f1414a42bb582905b199d360addae466d3ae",
+    "dist/2022-12-27/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "0f7ce917f14a1d42637fbbbc343473596becceb22634cb7c7cdee6beaa2b9ca1",
+    "dist/2022-12-27/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "49667bd902fb5fb2855e843ca5c1dcd453171f164a3dee2dcd9e09b0d9e1e57e",
+    "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d5a03695685afff4debff8e09f2d91db02d2ac29981a9ec230619c3e388ce1c9",
+    "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "db1aeb772a08f111d8f024164b570322f45ecab0f6db4e931b91971b2b982323",
+    "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "0e51f97b677b5c813862bba3e5a3b0884f0ecdf9b7c3676089625431a3d0cb2c",
+    "dist/2022-12-27/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f88c6c33ac3682f340ed60b4f62ee8ed61eb21069a1f0a912024d19e41c0d5c7",
+    "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "25abe3158ec3ab7c064341247d78ea265ad7e0dc2063837fb5cf0a3bea9d011e",
+    "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "1d430b8e35ebd63a79b34917edacebb76b2fa8f1cea4772ba2c4ef0340485fb3",
+    "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "1858d5ed21a3132af4b56c841cbabc9fb834d501946956a0e9aeeddfa095344f",
+    "dist/2022-12-27/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "17cc52dbd6ccbed4677ad52fa666ea10295c11209528e78ac190f01b5d509f87",
+    "dist/2022-12-27/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "3440edd99025f24f2640528d2d1c10047c834b93cb09a935c65ecfb72012e7d0",
+    "dist/2022-12-27/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7e1ff0a950db0ecbadef3a9ee55a593891f11a42c6c0ff59637074c8b5c4da74",
+    "dist/2022-12-27/rustc-beta-i686-pc-windows-gnu.tar.gz": "90487ff490c4e71ae62e28492cf49600f8f92e0f35f5d76a50eafcf4bbcf4bcb",
+    "dist/2022-12-27/rustc-beta-i686-pc-windows-gnu.tar.xz": "8b44fb934aba0eef296098bfc5a9f2994cdd595420ce10f4f310c5ee9d481071",
+    "dist/2022-12-27/rustc-beta-i686-pc-windows-msvc.tar.gz": "0fefda6b62234a43976ebf18d7cd62057cad5b494c750f2d9730f5df64cadb00",
+    "dist/2022-12-27/rustc-beta-i686-pc-windows-msvc.tar.xz": "c9eecbc06e7456bf5e383557a8e5720d00d09de640b8c46139121faadc354d74",
+    "dist/2022-12-27/rustc-beta-i686-unknown-linux-gnu.tar.gz": "8b17d032192aa17e52a3f08a074079561ad7ad6c439f9274aef228af93adacc3",
+    "dist/2022-12-27/rustc-beta-i686-unknown-linux-gnu.tar.xz": "c70638cad594097450a469837411b110e979c303727341623427e3c9e4e4f507",
+    "dist/2022-12-27/rustc-beta-mips-unknown-linux-gnu.tar.gz": "3669ff9024092ab467a1b95aec2cb1692810ee716739f31e3aee7d89e6bd6d7f",
+    "dist/2022-12-27/rustc-beta-mips-unknown-linux-gnu.tar.xz": "165859e42492e33bff634c80b6c96b13fd2252981b4be2821b96a6593933e22a",
+    "dist/2022-12-27/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "2ac418c0cdeb2382aea7296169d747f65349d7e6d5aebbdde7b377e985de354e",
+    "dist/2022-12-27/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "21ae51357508398527b6edd2e5fbb1745fda1c8db2683c40847216c0ce251d47",
+    "dist/2022-12-27/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "3eb68935676424aa8c68bc32b06c010c5c1302fa6f77e9b33e5543565562d176",
+    "dist/2022-12-27/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "0eeb58035b510a166b8506168f67850993e278888986773c779bee24d7a6ec11",
+    "dist/2022-12-27/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "f41d878b2e49beb9ee3a1bb8863ce1b81fae7100a786a78d9922bf8a4fd0dfc8",
+    "dist/2022-12-27/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "e0cd18973c7651cd2e1e041f92900375a045bef62754d432df539000aa5946c4",
+    "dist/2022-12-27/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "7206be82ba39971c6a734f4a89f7f750d581768d82253e31cd985fecd1d17c3e",
+    "dist/2022-12-27/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "f9ec2a3e98a3b94b170237386256c763d62925b430d0e12a289982c7c79d2bfc",
+    "dist/2022-12-27/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "32be7fe5f359cb2312c9bd966eb43b143b336b4acbdf118bf09221574f157b16",
+    "dist/2022-12-27/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "a8163a5b527b1ee932e06589d690c17d8848dbfa8504de6984a718579698abb2",
+    "dist/2022-12-27/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "3e875cb943dd0ffff907f6a582a64f923cb84a07ddd8b5e6f1ec2e1d4228342f",
+    "dist/2022-12-27/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "22537364de01be77a2a5d79486b1090dbee7b3273fc634073031f82576a61a14",
+    "dist/2022-12-27/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "230041ec7d0d4debc841abafe2f3314de51793d281a1077835d9190286a558f7",
+    "dist/2022-12-27/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2dafdb1a97469737123149608476c248a77ccebeb22834b6a2166fc30551a7ce",
+    "dist/2022-12-27/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "0bd96121550321138dad9f74f331eaefd77ab388843e5561c5c0cb32e9d80072",
+    "dist/2022-12-27/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "ecb02c8535c1518e589eefb10be17830010c40be61f3184576abe93e098d793d",
+    "dist/2022-12-27/rustc-beta-x86_64-apple-darwin.tar.gz": "600b83ea5c832dc6ad9746d74b7dbc8ea566adb9208c4260b183ef05078d2bff",
+    "dist/2022-12-27/rustc-beta-x86_64-apple-darwin.tar.xz": "175930f3062b433fc0a2b959917933bf3347d3f3e0900684785493d0ee9dc6f3",
+    "dist/2022-12-27/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "d1701678ee1d2f2e91f3c1f898f852593ec1b109e430c53c13bc2898b08bca3f",
+    "dist/2022-12-27/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "3400e923af537d28139b9d5d780caa039828e06677cbf499322614006552778c",
+    "dist/2022-12-27/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "d462ca50803b13e136fbfd49ac4a6e186e416041f3cdaa8b4fe72e628cc10555",
+    "dist/2022-12-27/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "81ca0992ec8306ff67b00f5f85f31c6617f78b7350116dd56df082c477c9069d",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-freebsd.tar.gz": "65fe64154264ab76bb94aa7f107efa9b58cb801c9aaabcc7e6ffa0ce14319ef9",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-freebsd.tar.xz": "cd6e9bfb6e8c08a46dce7bc623cfdc5a04e55c8377eaa3a75fae0bfe8e00b43e",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-illumos.tar.gz": "a66bb4b0d9dd9a21b54857c4fa7eb48a88789f0414fec4a1e36c798546c4b71f",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-illumos.tar.xz": "b63e6299e961b75d9c9bcb46e1dbc22b8fec89292ee6c8758edd43f4b89cb12e",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "c768beca1350bdcbcc31c7d3f30c3ccec0ab2bea0c28bc4c89cdd32d9780cd00",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "62a675d74274ddb4d8a9146c20942cb91b86e0c94a902169c2cf77f4d471d645",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "8f2b81b37bc34291f3d90bb6aec621da0ac760c39727bfd24449c288cc8cb3c3",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "053c313c9a751bf0102448866fad2a80ca67b9f79afce82ce03805430e2e695b",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-netbsd.tar.gz": "a9f42eb0ffdc4bef87669d8fb5163e81a5d82ff6baf631f159b7bccafe9df453",
+    "dist/2022-12-27/rustc-beta-x86_64-unknown-netbsd.tar.xz": "d1ea529e56d57132de1782396a767f8f00f30e2b5f7c9a5fa96c3289b43e3515",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "411b96fddfbcc90b4522e3f4e2d6e174f3440960e89193c97fcd5ca8afd62809",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "29db6fb11b411dc8351a8a8d1b148e81d9c87f9fb234b3a18722ee470b4d36c0",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "32ab437117791eb7113ac522ee4119e2e43722528141302772adf9cda7306b24",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "4d892f3c65ef8e32670ab3c3e8fb39a2ae623c59d1ff555ec94644254e954474",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "8bff3a1591d25d3e1acb70600e6cd54d712772247376ac5eb90a4b2aafd21a6a",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "b81b094d128a37b178da1eda7c72399a9da4bd614e697c53e9c4d78589f859f5",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "b3a685d1abe4ac639a0a3ea187b83ec660cd838e7c5c010ed60f8620d17df906",
+    "dist/2022-12-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "10b7563202520708fd27cc221ee8db34b368563eb1586be1395955ebf4313d6e",
+    "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "34e5ca3d51b51ccd97ded5e0c31c999a84f9d5ca5ee3d010e15212a97ab40567",
+    "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "16638ba8478861276c10847b989fd23de942cb82a9d4da9d92858c6800a39a9e",
+    "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "13fa3bf29e9d20291703bf2c03bc97cd8e2081d1c747b6835eb0a06f94dd5d19",
+    "dist/2022-12-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "98dd01d90657e43ab3a2b91673137cd6ae4c171633db1f1e4b68b2e90bcb9bab",
+    "dist/2022-12-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "1370e4c8ad5bab425c02fc924d5ac079ac1387368a3ea5d22c1cdc2edc9c6ba0",
+    "dist/2022-12-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8c312da4ccd992c303fa3f181dc46f9b01022f72061ef43b2fd5848736547870",
+    "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "0d7a87816f50452349bd26cefdd9f53f2d93a53243290ac59bd5de414407aa1e",
+    "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "982fc6783ad07235d375c4c8964104fdc64a009ea359cca532cc268a8249e88c",
+    "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "a5b76840e49a912a819809a2b4c73a0e750422fad4876d11b409a8ed49a77911",
+    "dist/2022-12-27/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "9566b6417a0bdb4c73272d167cc743b297db62f625449343a6f1ab60c52d5327",
+    "dist/2022-12-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "bf6cb5e886ce02a3f9b4b00a3696da0ee277af8f690f5a31119c5fce5779cd4d",
+    "dist/2022-12-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "7afa5129bc43346614869721e7094f65eba6681bb9b8ca8a3559925f29433f10",
+    "dist/2022-12-27/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "f9805697506a0c730299492fe04c53433c8c4deb70ca245ff1c2cf5151fe306e",
+    "dist/2022-12-27/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f5d7d5a841a7e7a5d749e52cdb118d2f2cec09de68835a42748db4b3a0a79979",
+    "dist/2022-12-27/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "dc903c64c969a3c21664263c2a30e9cb0dc42069a95f755545ce9648240a376e",
+    "dist/2022-12-27/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "de6591cc73244d99b3469d88439ad442f00037a1cdcaf5fdc5a694b52e47b2fb",
+    "dist/2022-12-27/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "f4e8dba56a1b90d5871bf8722a5ecd2027a4f101299880a8689f5cf46df2606a",
+    "dist/2022-12-27/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "496c19042848726db446cd3df4c52f3e8a5527002ca5492e2d6ef72528d6887a",
+    "dist/2022-12-27/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "58742a5c8230e8749b01058acea639d92d45090bcec6fb7eb1d8f356b0f08631",
+    "dist/2022-12-27/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "bbbdaa32d8d29c407133b0ef2851970da884032effeb85c271d57e58b7d38a44",
+    "dist/2022-12-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "1a8a59193dc15d331c3243a2cfaf5c81c023464becc4da63201583d2d2cdc27d",
+    "dist/2022-12-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "ee86ae7621804a7b57ccab06dc73b7d87453b53814d482ea43dc26dd01dae1c5",
+    "dist/2022-12-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "21a79a050e4461305e280ed7de7c0ade2774ad5230f671c76667be7bdbdc47af",
+    "dist/2022-12-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "033afa47c24a4887d40d62391f9f66b76dffdc1bd8f1ad622bfb14db91d7df03",
+    "dist/2022-12-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "01cea51850a7f676803f5f8f9a556a71bfb8e7a7e04cc5fc0e7d1b706473338b",
+    "dist/2022-12-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "720bf138fb2c541d8d8d0c60d6584cff692c932c6f383901f999e7b3d4078770",
+    "dist/2022-12-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "8c3f3fd601bc7d8670f6acfcda29206fd5590fb3a2a6cbb3794ba29cf749144d",
+    "dist/2022-12-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "8f1b43479a724197c7ac051c6a6d2a10bd87c6b24fed1d38c9e93f503c87e5b6",
+    "dist/2022-12-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "b38b6dc1e65cc0f5031d2045a90404f3b2ce2648884db1f658641e76168d0109",
+    "dist/2022-12-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "ed635e2388fcd3bbe94f497404b6787edd5e7471d6c6471345386a43444f46d1",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "457995f055ef35a2491326f95caf31376b21e3cc4c0316cf4536cb7604e472d3",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "d80b01e8c007da58250f7affea8d034a536437efd766eeb8de6d5b7feba9b0d5",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "ee2ab7683e75fa68ad482c81e546cd71b9209497f16a0590507e5de884f1e627",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "d08326f42bf7f38855e37c624a38923d09cbf162b666e8058891aff06ec017c8",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "e42ee4dfdd0aa342dd8192204fd6cfb503eaa0069f70776adbbca352d7e7b661",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "76ec230ae507729fb4ced016a45b0020775a9eef068c2b2e5ae6e3fcb451d32d",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "55f5c89950a81b00efc542c19b42cbfeb9c969af63280106fc78e8893df3d568",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "5a4cf3589d06e562ebed70bf0015af3e80f83de1c4d311c810ebf09feac640bf",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "fb44bc69be6c89c7245b914324e23284dbd9887ac0c1c4a65379344ce78cfb28",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8d34915b54cd8ea6abf0bff01546f31f74342e1d21128b1e14c32cdfd3505afd",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "d15403f81b36c0a2829ad2dee5c1edf39a993a13ccc57f01bb45c77898e3b9ec",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "4c0c61f404ec6bb87ab044c0850d116c577a2ff3cfda9ac1598a7858b4fe1a7d",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "8bc1fe0e2496769f52a576ccd13f706b26f706f060bebb2618e2c64c3831e2d3",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "bcb527bb736bea88bbbb6974ba388b11fe20596c2c178314bbfdad5e2db65fcc",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "8bffdf816b12c53d5443e2523c0960a37ab67c93590b0bb753fd5a026e67d368",
+    "dist/2022-12-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "bb5c947ab6dfa28fa7c3d7050e9c14c02eaedf2a4e06d290bee554f569be2c30"
   }
 }
index 2fb62e93ea36c0909f699aa2be526809afabc334..d5b48105ef26716dff4acbcb1e9c2dbe3b411062 100644 (file)
@@ -26,7 +26,7 @@
 // [r9] needs-llvm-components: aarch64
 // [r10] compile-flags: --target aarch64-apple-ios
 // [r10] needs-llvm-components: aarch64
-// [r11] compile-flags: --target aarch64-fuchsia
+// [r11] compile-flags: --target aarch64-unknown-fuchsia
 // [r11] needs-llvm-components: aarch64
 // [r12] compile-flags: --target aarch64-linux-android
 // [r12] needs-llvm-components: aarch64
 // [r74] needs-llvm-components: x86
 // [r75] compile-flags:--target x86_64-fortanix-unknown-sgx
 // [r75] needs-llvm-components: x86
-// [r76] compile-flags:--target x86_64-fuchsia
+// [r76] compile-flags:--target x86_64-unknown-fuchsia
 // [r76] needs-llvm-components: x86
 // [r77] compile-flags:--target x86_64-linux-android
 // [r77] needs-llvm-components: x86
index bd1a6599c3365c3276e134a85487a939d0cec556..7b5ae894311eff15f8d2e9184a23fbe426a230ac 100644 (file)
@@ -2,7 +2,7 @@
 
 // Once we're done with llvm 14 and earlier, this test can be deleted.
 
-#![crate_type="lib"]
+#![crate_type = "lib"]
 
 use std::mem::MaybeUninit;
 
@@ -17,8 +17,16 @@ pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
     Box::new(MaybeUninit::uninit())
 }
 
-// FIXME: add a test for a bigger box. Currently broken, see
-// https://github.com/rust-lang/rust/issues/58201.
+// https://github.com/rust-lang/rust/issues/58201
+#[no_mangle]
+pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
+    // CHECK-LABEL: @box_uninitialized2
+    // CHECK-NOT: store
+    // CHECK-NOT: alloca
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Box::new(MaybeUninit::uninit())
+}
 
 // Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
 // from the CHECK-NOT above. We don't check the attributes here because we can't rely
index e105e26f16a23c6db15cc840c45a946b8794e4ed..c82b56a71f5cfde9d3c9a90f2143841536110119 100644 (file)
@@ -1,6 +1,6 @@
 // compile-flags: -O
 // min-llvm-version: 15.0
-#![crate_type="lib"]
+#![crate_type = "lib"]
 
 use std::mem::MaybeUninit;
 
@@ -15,8 +15,16 @@ pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
     Box::new(MaybeUninit::uninit())
 }
 
-// FIXME: add a test for a bigger box. Currently broken, see
-// https://github.com/rust-lang/rust/issues/58201.
+// https://github.com/rust-lang/rust/issues/58201
+#[no_mangle]
+pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
+    // CHECK-LABEL: @box_uninitialized2
+    // CHECK-NOT: store
+    // CHECK-NOT: alloca
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Box::new(MaybeUninit::uninit())
+}
 
 // Hide the `allocalign` attribute in the declaration of __rust_alloc
 // from the CHECK-NOT above, and also verify the attributes got set reasonably.
index 44fee952307f29b5c43ef7ca60ae7826f5662a70..0f9e90f6ba77990d2c265057699170a5cd372dbe 100644 (file)
@@ -145,7 +145,7 @@ pub fn raw_struct(_: *const S) {
 
 // `Box` can get deallocated during execution of the function, so it should
 // not get `dereferenceable`.
-// CHECK: noalias noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
 #[no_mangle]
 pub fn _box(x: Box<i32>) -> Box<i32> {
   x
diff --git a/src/test/codegen/issue-103840.rs b/src/test/codegen/issue-103840.rs
new file mode 100644 (file)
index 0000000..f19d703
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -O
+#![crate_type = "lib"]
+
+pub fn foo(t: &mut Vec<usize>) {
+    // CHECK-NOT: __rust_dealloc
+    let mut taken = std::mem::take(t);
+    taken.pop();
+    *t = taken;
+}
diff --git a/src/test/codegen/issue-86106.rs b/src/test/codegen/issue-86106.rs
new file mode 100644 (file)
index 0000000..9ccbcb2
--- /dev/null
@@ -0,0 +1,62 @@
+// min-llvm-version: 15.0
+// compile-flags: -C opt-level=3 -Z merge-functions=disabled
+
+// The below two functions ensure that both `String::new()` and `"".to_string()`
+// produce the identical code.
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: define void @string_new
+#[no_mangle]
+pub fn string_new() -> String {
+    // CHECK-NOT: load i8
+    // CHECK: store i{{32|64}}
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    String::new()
+}
+
+// CHECK-LABEL: define void @empty_to_string
+#[no_mangle]
+pub fn empty_to_string() -> String {
+    // CHECK-NOT: load i8
+    // CHECK: store i{{32|64}}
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    "".to_string()
+}
+
+// The below two functions ensure that both `vec![]` and `vec![].clone()`
+// produce the identical code.
+
+// CHECK-LABEL: @empty_vec
+#[no_mangle]
+pub fn empty_vec() -> Vec<u8> {
+    // CHECK: store i{{32|64}}
+    // CHECK-NOT: load i8
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    vec![]
+}
+
+// CHECK-LABEL: @empty_vec_clone
+#[no_mangle]
+pub fn empty_vec_clone() -> Vec<u8> {
+    // CHECK: store i{{32|64}}
+    // CHECK-NOT: load i8
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store ptr
+    // CHECK-NEXT: getelementptr
+    // CHECK-NEXT: store i{{32|64}}
+    // CHECK-NEXT: ret void
+    vec![].clone()
+}
diff --git a/src/test/codegen/noalias-flag.rs b/src/test/codegen/noalias-flag.rs
new file mode 100644 (file)
index 0000000..a9ec61e
--- /dev/null
@@ -0,0 +1,23 @@
+// compile-flags: -O -Zmutable-noalias=no
+
+#![crate_type = "lib"]
+
+// `-Zmutable-noalias=no` should disable noalias on mut refs...
+
+// CHECK-LABEL: @test_mut_ref(
+// CHECK-NOT: noalias
+// CHECK-SAME: %x
+#[no_mangle]
+pub fn test_mut_ref(x: &mut i32) -> &mut i32 {
+    x
+}
+
+// ...but not on shared refs
+
+// CHECK-LABEL: @test_ref(
+// CHECK-SAME: noalias
+// CHECK-SAME: %x
+#[no_mangle]
+pub fn test_ref(x: &i32) -> &i32 {
+    x
+}
index ece2adbdf4325e4211468d0c87d1875824bce64f..b9c33914360ba08c6b9144c556fdde42ccf70de5 100644 (file)
@@ -131,6 +131,13 @@ pub struct Type13<'a> {
     member3: &'a Type13<'a>,
 }
 
+// Helper type to allow `Type14<Bar>` to be a unique ID
+pub struct Bar;
+
+// repr(transparent) parameterized type
+#[repr(transparent)]
+pub struct Type14<T>(T);
+
 pub fn foo0(_: ()) { }
 // CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]]
 pub fn foo1(_: c_void, _: ()) { }
@@ -425,6 +432,12 @@ pub fn foo145(_: Type13, _: Type13) { }
 // CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]]
 pub fn foo146(_: Type13, _: Type13, _: Type13) { }
 // CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]]
+pub fn foo147(_: Type14<Bar>) { }
+// CHECK: define{{.*}}foo147{{.*}}!type ![[TYPE147:[0-9]+]]
+pub fn foo148(_: Type14<Bar>, _: Type14<Bar>) { }
+// CHECK: define{{.*}}foo148{{.*}}!type ![[TYPE148:[0-9]+]]
+pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { }
+// CHECK: define{{.*}}foo149{{.*}}!type ![[TYPE149:[0-9]+]]
 
 // CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"}
 // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"}
@@ -570,6 +583,9 @@ pub fn foo146(_: Type13, _: Type13, _: Type13) { }
 // CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"}
 // CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"}
 // CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"}
-// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIu3refIvEEE"}
-// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_E"}
-// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_S0_E"}
+// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIvEE"}
+// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIvES_E"}
+// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"}
+// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarE
+// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_E
+// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_S_E
index 29d2a1754a3afb7f6202bada58ffd11eae9875ef..844d5870a846fa6c52f362b3a2e578990c5cd4cc 100644 (file)
@@ -15,7 +15,7 @@ pub fn helper(_: usize) {
 pub fn scalar_layout(s: &(u64, ())) {
 // CHECK: getelementptr i8, {{.+}}, [[USIZE]] 8
     let x = &s.1;
-    &x; // keep variable in an alloca
+    witness(&x); // keep variable in an alloca
 }
 
 // Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout
@@ -24,7 +24,7 @@ pub fn scalar_layout(s: &(u64, ())) {
 pub fn scalarpair_layout(s: &(u64, u32, ())) {
 // CHECK: getelementptr i8, {{.+}}, [[USIZE]] 12
     let x = &s.2;
-    &x; // keep variable in an alloca
+    witness(&x); // keep variable in an alloca
 }
 
 #[repr(simd)]
@@ -36,5 +36,8 @@ pub fn scalarpair_layout(s: &(u64, u32, ())) {
 pub fn vector_layout(s: &(U64x4, ())) {
 // CHECK: getelementptr i8, {{.+}}, [[USIZE]] 32
     let x = &s.1;
-    &x; // keep variable in an alloca
+    witness(&x); // keep variable in an alloca
 }
+
+#[inline(never)]
+fn witness(_: &impl Sized) {}
index dd3dce4e7209c746dfd49a479156ae8b6b23b060..83737a02200918225bc868fb2f5b78a011684042 100644 (file)
@@ -2,8 +2,6 @@
 // compile-flags: -Zquery-dep-graph
 // [rpass1]compile-flags: -Zincremental-ignore-spans
 // [rpass2]compile-flags: -Zincremental-ignore-spans
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
 
 #![feature(rustc_attrs)]
 #![rustc_partition_reused(module = "change_symbol_export_status-mod1", cfg = "rpass2")]
index f3a7722cdcad020aa0faf147bc720ef3586349d1..65df2e8292a047cf3ba9578040dde36925ae074e 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 
 #![allow(warnings)]
index c769246b29b2f9565a3c396ee5a79716261d9589..927bcd96e6f4b966b923eba40b6c41c93ee3af9d 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
@@ -45,9 +42,9 @@ pub fn add_parameter() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_parameter() {
     let x = 0u32;
index 70ef10645f19f3ab8ea25ab91a8930805efab064..db367d07094d7786d34e792938e303870f601c2b 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 0f8898c389b7f4b33a819f03ff42622696884748..bc83723a908f29bc5995b4efce419cd3ef4574a7 100644 (file)
@@ -16,9 +16,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 87fd21fd1b8107ccea5fdc8276dba39c770754d9..9ac9ae24f81bc524d701fa9cab4fc417c35fef2a 100644 (file)
@@ -4,9 +4,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 3121abbea369b04de3b071b4389f918b81ddf32b..1906843c7a247a569c95c9f6231a36d6549fde2f 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 16d6af01695f1965df01d432e9b941ba9eb21bc5..193e792c84330203c7a3aa3d5ed053e2726e356b 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 3ff949fbb3f808b5f6d7d20236f68aa09a24892f..182ca7d926c6bdd6c521a96374c25dec1e7e7c53 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(linkage)]
index cff557dcb74b8830e7ae14e93d9f0ab6b9741f13..937fd3ac879a920b1a74a89e319c56b28e6bead4 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 9ef46847243641bd3997a869be5b865234fdc8a3..b1ac6f6fa6c2b3acc846fd3f35a31a8e6ded4809 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 1abbff32c6f349ece60c2d60622a4bf3c6bc85e6..285f857c9cbcf7565ea9c832533aa8c0c6e5c322 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 
 #![allow(warnings)]
index dc878d6827cbf87f3b5ea96738b27c1d700cb1be..3118aa1356452985aaf66035a3a8c01de3fb7d63 100644 (file)
@@ -12,9 +12,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 01320cd51f4453d356a4c23a573fed3b9e7ddd0c..180bf6fec8772b72c22b3026b5189a16608d0863 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index ada541e644a3130236366d1b562303afe9059f38..87b86479d07bd9f8ed7146d5808fad1e0c6a0e72 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index fa054c7decc57056b3b1bcf1758f08e1cf664a42..4429df6833e486ec96a1007547058fce717a8a92 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 67d87f5c4ed92e7cad5c7f9d97f113e08a82e05a..bb83f8300d06d69169b40b3e00f07806a6d78b29 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index fc9671cb41b47ef529455ab52a8875a4d0573dc0..e50e5674c661e4ea96901ac744704d6f2296ebb2 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 7a91722d70fda1e4027728bbb078e8b7acbeb7bb..4a2706b4f0100817699a3c234502e467f364598c 100644 (file)
@@ -16,9 +16,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index c453eeceb77f53b1266e25a5eccef6a814f5a297..b583bee2f2449b8d34eab33e428e091769a97a13 100644 (file)
@@ -16,9 +16,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index f555f555f9236c7c214c78324d5ce8a345ed7094..3b2e18d17a96b51941e4e2aa68ca7cee3d5aefee 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 18fb716353fa7f55484b766af5477efd6245c2af..58af51eef077f1809a3a93ecc218baf13292af75 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 88fd4d89b2827661b9d9f74dcaf4be3e5692d4d7..c81b0d0afb8114fd16a1505eb61e5d3a166a4cdc 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 9b4d23757b871340e7418c03025e449d978ccf63..c1cc0b62bc2442ebff17709558d120ec88421fa9 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 639454cc975300dad6299d4a6cf761ad4450e5c7..38ab28461911b6e2a91acc587db5dc4b08ebb03f 100644 (file)
@@ -1,21 +1,17 @@
 // This test makes sure that just changing a definition's location in the
 // source file also changes its incr. comp. hash, if debuginfo is enabled.
 
-// revisions:rpass1 rpass2 rpass3 rpass4
+// revisions:rpass1 rpass2
 
 // ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g -Z query-dep-graph
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
 
 #![feature(rustc_attrs)]
 #![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass4")]
 
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
 pub fn main() {}
 
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
 pub fn main() {}
index 6f51c9729e3706e15e09cd655258c317d6fae109..085e4cd78ca1ce6718e34320b49e9e1e3dfcfd8e 100644 (file)
@@ -1,26 +1,22 @@
 // This test makes sure that just changing a definition's location in the
 // source file also changes its incr. comp. hash, if debuginfo is enabled.
 
-// revisions:rpass1 rpass2 rpass3 rpass4
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
+// revisions:rpass1 rpass2
 
 // compile-flags: -C overflow-checks=on -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")]
 
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
 pub fn main() {
     if std::hint::black_box(false) {
         panic!()
     }
 }
 
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
 pub fn main() {
     if std::hint::black_box(false) {
         panic!()
index cae7b4aab7565ed60455eec442a1a4de705760e2..e15a8d18f853dfd9bd43f12fd78c7a1f1ea8d256 100644 (file)
@@ -1,7 +1,5 @@
-// revisions: cfail1 cfail2 cfail3 cfail4
+// revisions: cfail1 cfail2
 // compile-flags: -Z query-dep-graph
-// [cfail3]compile-flags: -Zincremental-relative-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
 // build-pass (FIXME(62277): could be check-pass?)
 
 #![allow(warnings)]
 // needed even for callers of `x`.
 
 pub mod x {
-    #[cfg(any(cfail1, cfail3))]
+    #[cfg(cfail1)]
     pub fn x() {
         println!("{}", "1");
     }
 
-    #[cfg(any(cfail2, cfail4))]
-    #[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg = "cfail2")]
-    #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail4")]
+    #[cfg(cfail2)]
+    #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail2")]
     pub fn x() {
         println!("{}", "2");
     }
@@ -30,7 +27,6 @@ pub mod y {
     use x;
 
     #[rustc_clean(cfg = "cfail2")]
-    #[rustc_clean(cfg = "cfail4")]
     pub fn y() {
         x::x();
     }
@@ -40,7 +36,6 @@ pub mod z {
     use y;
 
     #[rustc_clean(cfg = "cfail2")]
-    #[rustc_clean(cfg = "cfail4")]
     pub fn z() {
         y::y();
     }
index 31f329a7f726b2083d9b80837fc98a57158038dd..368a726ea904de1a8164b3dd0c78ca483a1066e0 100644 (file)
@@ -3,10 +3,7 @@
 // ends up with any spans in its LLVM bitecode, so LLVM is able to skip
 // re-building any modules which import 'inlined_fn'
 
-// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
+// revisions: cfail1 cfail2 cfail3
 // compile-flags: -Z query-dep-graph -O
 // build-pass (FIXME(62277): could be check-pass?)
 
     cfg = "cfail3",
     kind = "post-lto"
 )]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-foo",
-    cfg = "cfail5",
-    kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-foo",
-    cfg = "cfail6",
-    kind = "post-lto"
-)]
 #![rustc_expected_cgu_reuse(
     module = "cgu_keeps_identical_fn-bar",
     cfg = "cfail2",
     cfg = "cfail3",
     kind = "post-lto"
 )]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-bar",
-    cfg = "cfail5",
-    kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-bar",
-    cfg = "cfail6",
-    kind = "post-lto"
-)]
 
 mod foo {
 
index da5a64cac651315e589ae6f541b0c829975dc532..6140fc52f650e88de055efd6559db8bedf63c29f 100644 (file)
@@ -10,12 +10,12 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
         _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
                                          // mir::Constant
-                                         // + span: $DIR/const_allocation.rs:8:5: 8:8
+                                         // + span: $DIR/const_allocation.rs:9:5: 9:8
                                          // + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
-        nop;                             // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
+        _0 = const ();                   // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
         return;                          // scope 0 at $DIR/const_allocation.rs:+2:2: +2:2
     }
 }
index febd990681e5679ce4247c55c4c87f2acbfbf184..b2ed23c6873cdf71e9ade7c9afa919652abf87e2 100644 (file)
@@ -10,12 +10,12 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
         _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
                                          // mir::Constant
-                                         // + span: $DIR/const_allocation.rs:8:5: 8:8
+                                         // + span: $DIR/const_allocation.rs:9:5: 9:8
                                          // + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation.rs:+1:5: +1:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation.rs:+1:8: +1:9
-        nop;                             // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
+        _0 = const ();                   // scope 0 at $DIR/const_allocation.rs:+0:11: +2:2
         return;                          // scope 0 at $DIR/const_allocation.rs:+2:2: +2:2
     }
 }
index b0fcb86fcee0f25f6567ca42849cc90844f1929d..91a2455eb836a94e1f4406b376f84a63d92a0509 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 static FOO: &[(Option<i32>, &[&str])] =
index 389641f20f422f90abcc128d7963514fb16858a4..aab005c52d6a02d4c05e984d53519289cfde1917 100644 (file)
@@ -10,12 +10,12 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
         _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
                                          // mir::Constant
-                                         // + span: $DIR/const_allocation2.rs:5:5: 5:8
+                                         // + span: $DIR/const_allocation2.rs:6:5: 6:8
                                          // + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
-        nop;                             // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
+        _0 = const ();                   // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
         return;                          // scope 0 at $DIR/const_allocation2.rs:+2:2: +2:2
     }
 }
index ce3848e9216c7d67691bef78bd9885acd0b82961..0eff9474c2051893fa7510d7f72963278a7b224d 100644 (file)
@@ -10,12 +10,12 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
         _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
                                          // mir::Constant
-                                         // + span: $DIR/const_allocation2.rs:5:5: 5:8
+                                         // + span: $DIR/const_allocation2.rs:6:5: 6:8
                                          // + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation2.rs:+1:5: +1:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation2.rs:+1:8: +1:9
-        nop;                             // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
+        _0 = const ();                   // scope 0 at $DIR/const_allocation2.rs:+0:11: +2:2
         return;                          // scope 0 at $DIR/const_allocation2.rs:+2:2: +2:2
     }
 }
index 30afedffb39b3d817b0124701c56f8ede105c5a6..f2870aa47c5635cca528c8fd003092bb0945bea7 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR const_allocation2.main.ConstProp.after.mir
index b72519159d758bb37bb4417a9df25a2b65227305..55c6db5d0ce91aeed98bbad0e085174782a982c5 100644 (file)
@@ -10,12 +10,12 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
         _2 = const {alloc1: &&Packed};   // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
                                          // mir::Constant
-                                         // + span: $DIR/const_allocation3.rs:5:5: 5:8
+                                         // + span: $DIR/const_allocation3.rs:6:5: 6:8
                                          // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
-        nop;                             // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
+        _0 = const ();                   // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
         return;                          // scope 0 at $DIR/const_allocation3.rs:+2:2: +2:2
     }
 }
index 6bd047c7d9fb27803cf2333d352aa7377276aae3..27492a7fd22c1780309074728ac03b25b06c4643 100644 (file)
@@ -10,12 +10,12 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
         _2 = const {alloc1: &&Packed};   // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
                                          // mir::Constant
-                                         // + span: $DIR/const_allocation3.rs:5:5: 5:8
+                                         // + span: $DIR/const_allocation3.rs:6:5: 6:8
                                          // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation3.rs:+1:5: +1:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation3.rs:+1:8: +1:9
-        nop;                             // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
+        _0 = const ();                   // scope 0 at $DIR/const_allocation3.rs:+0:11: +2:2
         return;                          // scope 0 at $DIR/const_allocation3.rs:+2:2: +2:2
     }
 }
index ddeb32ab9a583132579c132fcb1238bd97de3504..da3fd089b026be26238cd1f9a9e98430fce4060e 100644 (file)
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR const_allocation3.main.ConstProp.after.mir
index e959e1b2f2c309dee6b7caf45d22c320c0495745..dd548adde7e5fe0f05f5ddd7b8d6c642e92d7762 100644 (file)
@@ -8,8 +8,8 @@
       let mut _6: u8;                      // in scope 0 at $DIR/const_debuginfo.rs:+4:15: +4:16
       let mut _7: u8;                      // in scope 0 at $DIR/const_debuginfo.rs:+4:19: +4:20
       let mut _8: u8;                      // in scope 0 at $DIR/const_debuginfo.rs:+4:23: +4:24
-      let mut _14: u32;                    // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16
-      let mut _15: u32;                    // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22
+      let mut _12: u32;                    // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16
+      let mut _13: u32;                    // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22
       scope 1 {
 -         debug x => _1;                   // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10
 +         debug x => const 1_u8;           // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10
                       scope 5 {
 -                         debug s => _9;   // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
 +                         debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10
-                          let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
-                          let _16: bool;   // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
-                          let _17: bool;   // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
-                          let _18: u32;    // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+                          let _14: bool;   // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+                          let _15: bool;   // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
+                          let _16: u32;    // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
                           scope 6 {
-                              debug f => (bool, bool, u32){ .0 => _16, .1 => _17, .2 => _18, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10
-                              let _11: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
+                              debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10
+                              let _10: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
                               scope 7 {
-                                  debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10
-                                  let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
-                                  let _19: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
-                                  let _20: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
+                                  debug o => _10; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10
+                                  let _17: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
+                                  let _18: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
                                   scope 8 {
-                                      debug p => Point{ .0 => _19, .1 => _20, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10
-                                      let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
+                                      debug p => Point{ .0 => _17, .1 => _18, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10
+                                      let _11: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
                                       scope 9 {
--                                         debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
+-                                         debug a => _11; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
 +                                         debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10
                                       }
                                   }
                                            // mir::Constant
                                            // + span: $DIR/const_debuginfo.rs:14:13: 14:28
                                            // + literal: Const { ty: &str, val: Value(Slice(..)) }
+          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
-          StorageLive(_17);                // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10
-          StorageLive(_18);                // 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
-          Deinit(_17);                     // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          Deinit(_18);                     // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          _16 = const true;                // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          _17 = const false;               // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          _18 = const 123_u32;             // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34
-          StorageLive(_11);                // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10
-          Deinit(_11);                     // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
-          ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
-          discriminant(_11) = 1;           // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24
-          StorageLive(_19);                // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
-          StorageLive(_20);                // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10
-          Deinit(_19);                     // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
-          Deinit(_20);                     // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
-          _19 = const 32_u32;              // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
-          _20 = const 32_u32;              // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35
-          StorageLive(_13);                // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10
-          StorageLive(_14);                // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
-          _14 = const 32_u32;              // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16
-          StorageLive(_15);                // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
-          _15 = const 32_u32;              // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22
-          _13 = const 64_u32;              // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22
-          StorageDead(_15);                // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
-          StorageDead(_14);                // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22
-          nop;                             // scope 0 at $DIR/const_debuginfo.rs:+0:11: +14:2
-          StorageDead(_13);                // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_19);                // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_20);                // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_11);                // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2
+          _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
+          _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
           StorageDead(_16);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_17);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
-          StorageDead(_18);                // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_9);                 // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_4);                 // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2
           StorageDead(_3);                 // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2
index 22151304259bc674321c53a529201648cb5abc3b..8485703e39f2c5b1b68261bf650caf15ef2f49c8 100644 (file)
@@ -45,7 +45,6 @@
 -         _2 = Rem(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
           StorageDead(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
-          nop;                             // scope 0 at $DIR/bad_op_mod_by_zero.rs:+0:11: +3:2
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
index c27b19679a8396cdda5345064801d6b28b0d20e1..27e41d4869d759b74f8cad5bbc981311a0b7cb26 100644 (file)
@@ -6,17 +6,16 @@
       let _1: *const [i32];                // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
       let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
-      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+      let _5: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+      let mut _6: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _8: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           scope 2 {
-              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+              let _4: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               scope 3 {
-                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+                  debug _b => _4;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               }
           }
       }
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _9 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _3 = _8;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
           StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
-          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
-          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         _8 = Lt(const 3_usize, _7);      // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _6 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         _7 = Lt(_5, _6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         _7 = Lt(const 3_usize, _6);      // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
       }
   
       bb1: {
-          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
-          nop;                             // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
-          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+          _4 = (*_1)[_5];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+          StorageDead(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
       }
index c27b19679a8396cdda5345064801d6b28b0d20e1..27e41d4869d759b74f8cad5bbc981311a0b7cb26 100644 (file)
@@ -6,17 +6,16 @@
       let _1: *const [i32];                // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
       let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
-      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+      let _5: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+      let mut _6: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _8: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           scope 2 {
-              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+              let _4: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               scope 3 {
-                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+                  debug _b => _4;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               }
           }
       }
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _9 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _3 = _8;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
           StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
-          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
-          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         _8 = Lt(const 3_usize, _7);      // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _6 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         _7 = Lt(_5, _6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         _7 = Lt(const 3_usize, _6);      // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
       }
   
       bb1: {
-          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
-          nop;                             // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
-          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+          _4 = (*_1)[_5];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+          StorageDead(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
       }
index 147670f8a915c4681eb853556097617f52ebf063..f270ab8b69f0ed43f6754f762623c41a1ae25120 100644 (file)
@@ -25,7 +25,6 @@
       }
   
       bb2: {
-          nop;                             // scope 0 at $DIR/control_flow_simplification.rs:+3:6: +3:6
           StorageDead(_1);                 // scope 0 at $DIR/control_flow_simplification.rs:+3:5: +3:6
           return;                          // scope 0 at $DIR/control_flow_simplification.rs:+4:2: +4:2
       }
index 67a4dc3c092698f1c97f95197d0eaac454000d98..6c4757c1a81036cc1102860e69edde66bc79d750 100644 (file)
@@ -7,8 +7,6 @@
       let mut _2: main::InvalidChar;       // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
       let mut _4: E;                       // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
       let mut _5: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
-      let mut _7: Empty;                   // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
-      let mut _8: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
       scope 1 {
           debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
           let _3: [E; 1];                  // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
@@ -17,9 +15,9 @@
               let _6: [Empty; 1];          // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
               scope 5 {
                   debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
-                  let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+                  let _7: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
                   scope 7 {
-                      debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
+                      debug _non_utf8_str => _7; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
                   }
               }
               scope 6 {
           StorageDead(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
           StorageDead(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
           StorageLive(_6);                 // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
-          StorageLive(_7);                 // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
-          StorageLive(_8);                 // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
-          Deinit(_8);                      // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
-          (_8.0: u32) = const 0_u32;       // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
-          nop;                             // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
-          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
-          StorageDead(_7);                 // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
-          StorageDead(_8);                 // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
-          StorageLive(_9);                 // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
-          nop;                             // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
-          StorageDead(_9);                 // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
+          StorageLive(_7);                 // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+          StorageDead(_7);                 // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_6);                 // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
index 7d8e647cbcede741f0656e056fbbd66205546905..488e772d0ea8b3c735129c3db20d0b71a0aec860 100644 (file)
@@ -5,18 +5,13 @@
       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
-          StorageLive(_3);                 // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
-          nop;                             // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
           Deinit(_2);                      // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
-          nop;                             // 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
-          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
@@ -26,7 +21,6 @@
       bb1: {
           StorageDead(_2);                 // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23
           StorageDead(_1);                 // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24
-          nop;                             // scope 0 at $DIR/issue_66971.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2
       }
   }
index 79cd8bf483969fb1bfb98a0003e352be82408574..cd53048597b82083e9e58e0e8770c24ac7b6af17 100644 (file)
@@ -27,7 +27,6 @@
       bb1: {
           StorageDead(_2);                 // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20
           StorageDead(_1);                 // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21
-          nop;                             // scope 0 at $DIR/issue_67019.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2
       }
   }
index 96de39258e4ddcb6fe86e154133474c90848971f..5331e5b82122e301908e60caf444cb897fc89b3f 100644 (file)
@@ -29,7 +29,6 @@
           _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
           StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
           StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
-          nop;                             // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
       }
index 96de39258e4ddcb6fe86e154133474c90848971f..5331e5b82122e301908e60caf444cb897fc89b3f 100644 (file)
@@ -29,7 +29,6 @@
           _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
           StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
           StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
-          nop;                             // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
       }
index 3bbd6a87f97144bf6f3edfe57bebc2fdaa82856e..a672c457a72b13d5c7e694ef63f64f8ce1732ac0 100644 (file)
@@ -19,7 +19,6 @@
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable.rs:+3:9: +3:10
 -         _2 = _1;                         // scope 1 at $DIR/mutable_variable.rs:+3:13: +3:14
 +         _2 = const 99_i32;               // scope 1 at $DIR/mutable_variable.rs:+3:13: +3:14
-          nop;                             // scope 0 at $DIR/mutable_variable.rs:+0:11: +4:2
           StorageDead(_2);                 // scope 1 at $DIR/mutable_variable.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/mutable_variable.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/mutable_variable.rs:+4:2: +4:2
index fed6a98b9f3644ef11aa7f7d7ec36e5a2c9fbcb8..f6bf522065bac59ff89dee8edb63e5cc4785ab90 100644 (file)
@@ -21,7 +21,6 @@
           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
-          nop;                             // scope 0 at $DIR/mutable_variable_aggregate.rs:+0:11: +4:2
           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
           return;                          // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:2: +4:2
index 90eebd8feac60e2fe6b98cb34aba6ce9a43303fa..213a70227d876324abbc04286d9971d128596929 100644 (file)
@@ -26,7 +26,6 @@
           ((*_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
-          nop;                             // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+0:11: +5:2
           StorageDead(_3);                 // 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
index 6eda503c1eec4c615afcb8e467988fc186447935..149aa6290d0ea5d62baf67188f1a1eed3fb585f8 100644 (file)
@@ -26,7 +26,6 @@
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:9: +4:10
 -         _2 = (_1.1: i32);                // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:13: +4:16
 +         _2 = const 99_i32;               // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+4:13: +4:16
-          nop;                             // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+0:11: +5:2
           StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:1: +5:2
           StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+5:2: +5:2
index eb3a7bc96d8822cdf959be5ac9ca55daecc246d0..b9d551c5e5fc26a318b368d671927eb65ac77146 100644 (file)
@@ -4,39 +4,34 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_no_prop.rs:+0:11: +0:11
       let mut _1: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14
-      let _2: ();                          // in scope 0 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6
-      let mut _3: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
-      let mut _4: *mut u32;                // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+      let mut _2: u32;                     // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+      let mut _3: *mut u32;                // in scope 0 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
       scope 1 {
           debug x => _1;                   // in scope 1 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14
-          let _5: u32;                     // in scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
+          let _4: u32;                     // in scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
           scope 2 {
           }
           scope 3 {
-              debug y => _5;               // in scope 3 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
+              debug y => _4;               // in scope 3 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
           }
       }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:+1:9: +1:14
           _1 = const 42_u32;               // scope 0 at $DIR/mutable_variable_no_prop.rs:+1:17: +1:19
-          StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6
+          StorageLive(_2);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
           StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
-          StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
-          _4 = const {alloc1: *mut u32};   // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+          _3 = const {alloc1: *mut u32};   // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable_no_prop.rs:10:13: 10:19
                                            // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) }
-          _3 = (*_4);                      // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
-          _1 = move _3;                    // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19
-          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:18: +3:19
-          StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:19: +3:20
-          nop;                             // scope 2 at $DIR/mutable_variable_no_prop.rs:+2:5: +4:6
-          StorageDead(_2);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:+4:5: +4:6
-          StorageLive(_5);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
-          _5 = _1;                         // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:13: +5:14
-          nop;                             // scope 0 at $DIR/mutable_variable_no_prop.rs:+0:11: +6:2
-          StorageDead(_5);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2
+          _2 = (*_3);                      // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
+          _1 = move _2;                    // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19
+          StorageDead(_2);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:18: +3:19
+          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:19: +3:20
+          StorageLive(_4);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:9: +5:10
+          _4 = _1;                         // scope 1 at $DIR/mutable_variable_no_prop.rs:+5:13: +5:14
+          StorageDead(_4);                 // scope 1 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2
           StorageDead(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/mutable_variable_no_prop.rs:+6:2: +6:2
       }
index 2e4b0e79e9f2d355fc142aec38583a648603eaa7..c3f77b960a2dc1b2bccaf4c1114051b436e5310e 100644 (file)
@@ -4,20 +4,19 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +0:11
       let _1: i32;                         // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
-      let mut _3: i32;                     // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
+      let mut _2: i32;                     // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
-          let mut _2: (i32, i32);          // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
+          let mut _5: i32;                 // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
           let mut _6: i32;                 // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
-          let mut _7: i32;                 // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
           scope 2 {
-              debug x => (i32, i32){ .0 => _6, .1 => _7, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
-              let _4: i32;                 // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
+              debug x => (i32, i32){ .0 => _5, .1 => _6, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14
+              let _3: i32;                 // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
               scope 3 {
-                  debug y => _4;           // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
-                  let _5: i32;             // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
+                  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 => _5;       // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
+                      debug z => _4;       // 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
-          StorageLive(_7);                 // 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
-          Deinit(_7);                      // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
-          _6 = const 1_i32;                // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
-          _7 = const 2_i32;                // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35
-          StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
-          _3 = _1;                         // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
-          _7 = move _3;                    // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12
-          StorageDead(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
-          StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
-          _4 = _7;                         // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
-          StorageLive(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
--         _5 = _6;                         // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
-+         _5 = const 1_i32;                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
-          nop;                             // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2
-          StorageDead(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
-          StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
+          _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
+          _2 = _1;                         // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12
+          _6 = move _2;                    // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +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(_7);                 // 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 7e8ebd31ad1e94d016711359fea210e54ed62063..7c7aeac4c451bf0aa3c8a5d4c169ba9ba0c9accf 100644 (file)
@@ -9,9 +9,7 @@
       let _5: usize;                       // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
       let mut _6: usize;                   // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
       let mut _7: bool;                    // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
-      let mut _9: Point;                   // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-      let mut _10: u32;                    // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-      let mut _11: u32;                    // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+      let mut _9: 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 _3: i32;                     // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
           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(_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
-          _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
--         _8 = _11;                        // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+          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(_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 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
+          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
index 7e8ebd31ad1e94d016711359fea210e54ed62063..7c7aeac4c451bf0aa3c8a5d4c169ba9ba0c9accf 100644 (file)
@@ -9,9 +9,7 @@
       let _5: usize;                       // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33
       let mut _6: usize;                   // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
       let mut _7: bool;                    // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34
-      let mut _9: Point;                   // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-      let mut _10: u32;                    // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
-      let mut _11: u32;                    // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36
+      let mut _9: 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 _3: i32;                     // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10
           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(_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
-          _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
--         _8 = _11;                        // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38
+          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(_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 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2
+          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
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir
new file mode 100644 (file)
index 0000000..d926b9d
--- /dev/null
@@ -0,0 +1,27 @@
+// MIR for `main` after SimplifyLocals-final
+
+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
+    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
+            }
+        }
+    }
+
+    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
+    }
+}
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir
new file mode 100644 (file)
index 0000000..d926b9d
--- /dev/null
@@ -0,0 +1,27 @@
+// MIR for `main` after SimplifyLocals-final
+
+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
+    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
+            }
+        }
+    }
+
+    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
+    }
+}
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir
deleted file mode 100644 (file)
index 75cea8a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `main` after SimplifyLocals
-
-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
-    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
-            }
-        }
-    }
-
-    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
-    }
-}
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir
deleted file mode 100644 (file)
index 75cea8a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `main` after SimplifyLocals
-
-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
-    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
-            }
-        }
-    }
-
-    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 025666548180bda652f0ce3e439550d37592acc4..abea07e2025b77b28b33fbe0b059a8d9d08acf8f 100644 (file)
@@ -9,7 +9,7 @@ struct Point {
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR optimizes_into_variable.main.ScalarReplacementOfAggregates.diff
 // EMIT_MIR optimizes_into_variable.main.ConstProp.diff
-// EMIT_MIR optimizes_into_variable.main.SimplifyLocals.after.mir
+// EMIT_MIR optimizes_into_variable.main.SimplifyLocals-final.after.mir
 // EMIT_MIR optimizes_into_variable.main.PreCodegen.after.mir
 fn main() {
     let x = 2 + 2;
index b9c283a54821b7576aa1edb8717ad2daf9d64501..388c6ca810b6e724851d3969705a06b6a2633306 100644 (file)
@@ -36,7 +36,6 @@
           StorageDead(_2);                 // scope 0 at $DIR/read_immutable_static.rs:+1:21: +1:22
           StorageDead(_5);                 // scope 0 at $DIR/read_immutable_static.rs:+1:22: +1:23
           StorageDead(_3);                 // scope 0 at $DIR/read_immutable_static.rs:+1:22: +1:23
-          nop;                             // scope 0 at $DIR/read_immutable_static.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/read_immutable_static.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/read_immutable_static.rs:+2:2: +2:2
       }
index 09ce67ff15dd5af6ca5f40924f411d15234b9f11..8a73f0390e122fab4b66423fe548ef3ac0759051 100644 (file)
@@ -13,7 +13,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
           _4 = const _;                    // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref.rs:5:6: 5:10
+                                           // + span: $DIR/ref_deref.rs:6:6: 6:10
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
 -         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
index 902cd7850311450f8c57f68af4cb93e305241e17..015ec4d078c10cc1d9da5bc035cf4134d127af0f 100644 (file)
@@ -16,7 +16,7 @@
 -         _2 = &_3;                        // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
 +         _4 = const _;                    // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
 +                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref.rs:5:6: 5:10
++                                          // + span: $DIR/ref_deref.rs:6:6: 6:10
 +                                          // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
 +         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10
index 30ec9766367baf01e72cc267b1081e592f723db5..d2549c8b6aa5aa13277bcc168dc6edb04f277264 100644 (file)
@@ -1,3 +1,4 @@
+// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
 // EMIT_MIR ref_deref.main.PromoteTemps.diff
 // EMIT_MIR ref_deref.main.ConstProp.diff
 
index 659c11d9b0c29f4afae77f07b26913976bce623e..2fdd4e15319014cd28efabf768483b81bcd84044 100644 (file)
@@ -1,4 +1,4 @@
-// unit-test
+// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
 // EMIT_MIR ref_deref_project.main.PromoteTemps.diff
 // EMIT_MIR ref_deref_project.main.ConstProp.diff
 
index 237a6f94aa7fde594d691b5b5b3f5822808dc275..15c93f270d70732a7b7b8a98d57190efcc641f4b 100644 (file)
@@ -3,26 +3,21 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +0:11
-      let mut _1: *const fn();             // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
-      let mut _2: usize;                   // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-      let mut _3: fn();                    // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+      let mut _1: usize;                   // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+      let mut _2: fn();                    // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
       scope 1 {
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
-          StorageLive(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-          StorageLive(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
-          _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+          StorageLive(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+          StorageLive(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+          _2 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
                                            // mir::Constant
                                            // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
                                            // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
-          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-          StorageDead(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
-          _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
-          StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
-          StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:41: +1:42
-          nop;                             // scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +2:2
+          _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+          StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
+          StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
           return;                          // scope 0 at $DIR/reify_fn_ptr.rs:+2:2: +2:2
       }
   }
index 7c4977996917eb46f2f9f1f554cc60aabc232f51..636032adb819133a517fb3202e23f17c8908a57d 100644 (file)
@@ -35,7 +35,6 @@
           StorageDead(_2);                 // scope 0 at $DIR/repeat.rs:+1:31: +1:32
           StorageDead(_4);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
-          nop;                             // scope 0 at $DIR/repeat.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/repeat.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/repeat.rs:+2:2: +2:2
       }
index 7c4977996917eb46f2f9f1f554cc60aabc232f51..636032adb819133a517fb3202e23f17c8908a57d 100644 (file)
@@ -35,7 +35,6 @@
           StorageDead(_2);                 // scope 0 at $DIR/repeat.rs:+1:31: +1:32
           StorageDead(_4);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
-          nop;                             // scope 0 at $DIR/repeat.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/repeat.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/repeat.rs:+2:2: +2:2
       }
index 5920937e0fd4f100070e0cc94716a5d48b1803c7..d518eff04eba21af52d1036f9ba2c6a2f808b444 100644 (file)
@@ -27,7 +27,6 @@
       bb1: {
           StorageDead(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
           StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
-          nop;                             // scope 0 at $DIR/scalar_literal_propagation.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
       }
index 44445731e72090a365113c15b0fac97251217604..9017fd18e48752f510e3326a1fbcfdcc1d49f6c9 100644 (file)
@@ -20,7 +20,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _9 = const _;                    // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
                                            // mir::Constant
-                                           // + span: $DIR/slice_len.rs:5:6: 5:19
+                                           // + span: $DIR/slice_len.rs:6:6: 6:19
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
index 44445731e72090a365113c15b0fac97251217604..9017fd18e48752f510e3326a1fbcfdcc1d49f6c9 100644 (file)
@@ -20,7 +20,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _9 = const _;                    // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
                                            // mir::Constant
-                                           // + span: $DIR/slice_len.rs:5:6: 5:19
+                                           // + span: $DIR/slice_len.rs:6:6: 6:19
                                            // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:+1:6: +1:19
index fa9eafa8b0beb48e738c6247e11f6a850c86a97d..eaaf34b960eb66a84bd0ef5f43aa95c3b26e3bcc 100644 (file)
@@ -1,3 +1,4 @@
+// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR slice_len.main.ConstProp.diff
index a0603c60dc79c534fc25e55e8d20d3375ccfbae1..e4c92b617c6a31180d3888899e8b05ec6d046f96 100644 (file)
@@ -28,7 +28,6 @@
       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
-          nop;                             // scope 0 at $DIR/tuple_literal_propagation.rs:+0:11: +4:2
           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 459da2e335851a4082d7cafee84417cdcd151494..ea9fec0aa15d1a6f0c09371fbbe1ecacb9bc2a98 100644 (file)
@@ -4,16 +4,15 @@
   fn bar() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10
       let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
-      let _2: ();                          // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
-      let mut _3: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-      let mut _5: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+      let mut _2: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+      let mut _4: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
       scope 1 {
           debug v => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
-          let _4: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+          let _3: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
           scope 2 {
           }
           scope 3 {
-              debug y => _4;               // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+              debug y => _3;               // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
           }
       }
   
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
           Deinit(_1);                      // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
-          StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-          _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
-          (*_3) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
-          StorageDead(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
-          nop;                             // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
-          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6
-          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
-          StorageLive(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
-          _5 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
-          _4 = Eq(move _5, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
-          StorageDead(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
-          nop;                             // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2
-          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
+          StorageLive(_2);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+          _2 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
+          (*_2) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26
+          StorageDead(_2);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27
+          StorageLive(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20
+          _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18
+          _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25
+          StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2
       }
index e8bd98cf8cba103da7cc0aa8f6f55d92c69f468f..043f404741710a9af58bb2d0f7d7781e350659f9 100644 (file)
@@ -27,7 +27,6 @@
           _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18
           _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25
           StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25
-          nop;                             // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2
           StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2
index bf4557ed3d92c18f586b0a58a34bb73b2b2ced3a..02aafd7acc4ca5660cae57c17a18394031362f13 100644 (file)
@@ -5,40 +5,34 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inherit_overflow.rs:+0:11: +0:11
       let mut _1: u8;                      // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
       let mut _2: u8;                      // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-      let mut _3: u8;                      // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
       scope 1 {
       }
       scope 2 (inlined <u8 as Add>::add) { // at $DIR/inherit_overflow.rs:7:13: 7:47
-          debug self => _2;                // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          debug other => _3;               // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          debug self => _1;                // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          debug other => _2;               // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          let mut _3: u8;                  // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           let mut _4: u8;                  // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          let mut _5: u8;                  // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          let mut _6: (u8, bool);          // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          let mut _5: (u8, bool);          // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
       }
   
       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 u8::MAX;              // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageLive(_3);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          _3 = const 1_u8;                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+          _2 = const 1_u8;                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+          StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          _3 = const u8::MAX;              // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _4 = const u8::MAX;              // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _5 = const 1_u8;                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          _6 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          assert(!move (_6.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
+          _4 = const 1_u8;                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
+          assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
       }
   
       bb1: {
--         _1 = move (_6.0: u8);            // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-+         _1 = const 0_u8;                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
-          StorageDead(_3);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
+          StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           StorageDead(_2);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
-          StorageDead(_1);                 // scope 0 at $DIR/inherit_overflow.rs:+3:47: +3:48
-          nop;                             // scope 0 at $DIR/inherit_overflow.rs:+0:11: +4:2
+          StorageDead(_1);                 // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
           return;                          // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2
       }
   }
index 80f8905adc92d93ae714a7b326a16ec22e6f11cd..cd3b792fb751d9bbf592e6c72dd0d62033ba48a0 100644 (file)
 -         _4 = const ();                   // scope 0 at $DIR/cycle.rs:+3:18: +8:6
 -         StorageDead(_6);                 // scope 0 at $DIR/cycle.rs:+8:5: +8:6
 +         StorageLive(_5);                 // scope 0 at $DIR/cycle.rs:+4:13: +4:17
-+         nop;                             // scope 0 at $DIR/cycle.rs:+4:20: +4:21
-+         nop;                             // scope 1 at $DIR/cycle.rs:+5:13: +5:14
-+         nop;                             // scope 1 at $DIR/cycle.rs:+5:9: +5:14
-+         nop;                             // scope 1 at $DIR/cycle.rs:+6:13: +6:14
-+         nop;                             // scope 1 at $DIR/cycle.rs:+6:9: +6:14
-+         nop;                             // scope 1 at $DIR/cycle.rs:+7:13: +7:17
-+         nop;                             // scope 1 at $DIR/cycle.rs:+7:9: +7:17
-+         nop;                             // scope 0 at $DIR/cycle.rs:+3:18: +8:6
           StorageDead(_5);                 // scope 0 at $DIR/cycle.rs:+8:5: +8:6
 +         StorageDead(_4);                 // scope 0 at $DIR/cycle.rs:+8:5: +8:6
           goto -> bb1;                     // scope 0 at $DIR/cycle.rs:+3:5: +8:6
index ba7f76d2841f3465cc4133af4a82a44d2874785f..26068931aaf2cc0052bb607636efeaea43c90dfd 100644 (file)
@@ -13,7 +13,6 @@ fn f(_1: usize) -> usize {
     bb0: {
         nop;                             // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10
         nop;                             // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14
-        nop;                             // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10
         nop;                             // scope 1 at $DIR/dead_stores_better.rs:+3:9: +3:10
         nop;                             // scope 1 at $DIR/dead_stores_better.rs:+3:9: +3:10
         nop;                             // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10
index 85d994bc8b973442db7d3fbd54d87e559b34fa52..fbed3178801f0a275a451d3bb2fb577634a1ddba 100644 (file)
       }
   
       bb1: {
-          nop;                             // scope 0 at $DIR/union.rs:+5:14: +5:30
-          nop;                             // scope 0 at $DIR/union.rs:+5:14: +5:30
           StorageDead(_2);                 // scope 0 at $DIR/union.rs:+5:29: +5:30
           StorageLive(_3);                 // scope 1 at $DIR/union.rs:+7:10: +7:26
-          nop;                             // scope 2 at $DIR/union.rs:+7:19: +7:24
           StorageDead(_3);                 // scope 1 at $DIR/union.rs:+7:26: +7:27
           StorageDead(_1);                 // scope 0 at $DIR/union.rs:+8:1: +8:2
           return;                          // scope 0 at $DIR/union.rs:+8:2: +8:2
diff --git a/src/test/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir b/src/test/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..d7f66a6
--- /dev/null
@@ -0,0 +1,17 @@
+// MIR for `const_dividend` after PreCodegen
+
+fn const_dividend(_1: i32) -> i32 {
+    debug a => _1;                       // in scope 0 at $DIR/div_overflow.rs:+0:23: +0:24
+    let mut _0: i32;                     // return place in scope 0 at $DIR/div_overflow.rs:+0:34: +0:37
+    let mut _2: bool;                    // in scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+
+    bb0: {
+        _2 = Eq(_1, const 0_i32);        // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        assert(!move _2, "attempt to divide `{}` by zero", const 256_i32) -> bb1; // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+    }
+
+    bb1: {
+        _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        return;                          // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir b/src/test/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..7b7ab19
--- /dev/null
@@ -0,0 +1,11 @@
+// MIR for `const_divisor` after PreCodegen
+
+fn const_divisor(_1: i32) -> i32 {
+    debug a => _1;                       // in scope 0 at $DIR/div_overflow.rs:+0:22: +0:23
+    let mut _0: i32;                     // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36
+
+    bb0: {
+        _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12
+        return;                          // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/div_overflow.rs b/src/test/mir-opt/div_overflow.rs
new file mode 100644 (file)
index 0000000..10ce5bc
--- /dev/null
@@ -0,0 +1,18 @@
+// compile-flags: -Copt-level=0 -Coverflow-checks=yes
+
+// Tests that division with a const does not emit a panicking branch for overflow
+
+// EMIT_MIR div_overflow.const_divisor.PreCodegen.after.mir
+pub fn const_divisor(a: i32) -> i32 {
+    a / 256
+}
+
+// EMIT_MIR div_overflow.const_dividend.PreCodegen.after.mir
+pub fn const_dividend(a: i32) -> i32 {
+    256 / a
+}
+
+fn main() {
+    const_divisor(123);
+    const_dividend(123);
+}
index afe157ccd7faa3d08361122791c41967f3014620..5f3ee467c88cb026144d63eff156b74d19306742 100644 (file)
@@ -10,6 +10,8 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/cycle.rs:6:5: 6:6
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
 +     }
 + 
-+     bb4 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
index bd89e09ecd148b4e52384621802be95f24c94e43..6b4c63bbd917f61b488587ec177c7ec8d02b848a 100644 (file)
@@ -10,6 +10,8 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/cycle.rs:6:5: 6:6
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
 +     }
 + 
-+     bb4 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
index d9fd7b324c7619e79a1fa373b9ebba312225d8c6..7fd62be7ab9c35cedea97f6a4727f9742a89d107 100644 (file)
@@ -8,43 +8,68 @@
 +         let _2: ();                      // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
 +         let _3: ();                      // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
 +         let _4: ();                      // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
++             let _5: ();                  // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++             let _6: ();                  // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++             let _7: ();                  // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 -         _1 = <() as G>::call() -> bb1;   // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 +         StorageLive(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         _2 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageLive(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++         _5 = <() as E>::call() -> bb3;   // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
                                            // mir::Constant
 -                                          // + span: $DIR/exponential_runtime.rs:86:5: 86:20
 -                                          // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
-+                                          // + span: $DIR/exponential_runtime.rs:73:9: 73:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/exponential_runtime.rs:61:9: 61:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
-+         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
-+         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+         _3 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
 +         StorageDead(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
 +         StorageLive(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+         _4 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         _4 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
 +                                          // mir::Constant
 +                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
 +                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
 +     }
 + 
-+     bb3: {
++     bb2: {
 +         StorageDead(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
           StorageDead(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
           _0 = const ();                   // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
++     }
++ 
++     bb3: {
++         StorageDead(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
++         StorageLive(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++         _6 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb4: {
++         StorageDead(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
++         StorageLive(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         _7 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb5: {
++         StorageDead(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
++         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _3 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
       }
   }
   
index f54a1a747d47436aba941cb1ab4df23f43bad2b4..5510cd7bc8ced1d003fbd3b3fd914263c1466c44 100644 (file)
@@ -5,17 +5,20 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
++         scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
++             scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
++             }
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+         _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
++         _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle.rs:14:5: 14:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
-+                                          // + span: $DIR/inline_cycle.rs:43:9: 43:21
-+                                          // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/inline_cycle.rs:36:9: 36:26
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
index a940848c269cda8d5a5a98dd968f334f687dd0a4..64c0065b5436dea0b630e1879b8a39ec1d2b8e5d 100644 (file)
@@ -9,6 +9,8 @@
 +         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
 +         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         let mut _4: ();                  // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
++         }
 +     }
   
       bb0: {
                                            // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_cycle.rs:54:5: 54:6
-+                                          // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
++         _3 = move _2() -> bb1;           // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
index 04de3e61e5ff81f6b148d18fae783ac62bad7dc8..52debab4dd1c0348ed20ea66294415146254c6f6 100644 (file)
@@ -6,18 +6,21 @@
       let _1: ();                          // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
 +         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
++             scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
++                 scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
++                 }
++             }
 +         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+         _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++         _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
 +                                          // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-+                                          // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
index a01bcf1645b0571fe7f662353b5bf6ce1db23725..f82fcf4c82129634ee7d4a2288e85226031378fe 100644 (file)
@@ -20,6 +20,8 @@
 +                 debug b => _9;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
 +             }
 +         }
++         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
++         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         _4 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         StorageLive(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_diverging.rs:27:13: 27:14
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
 +     }
 + 
 +     bb1: {
-+         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
 +         StorageDead(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageDead(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageLive(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
 +         (_1.1: !) = move _9;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
 +         StorageDead(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
 +         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb2;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
-+     bb3: {
++     bb2: {
 +         unreachable;                     // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
 +     }
 + 
++     bb3 (cleanup): {
++         drop(_3) -> bb4;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++     }
++ 
 +     bb4 (cleanup): {
-+         drop(_3) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
 +     bb5 (cleanup): {
-+         drop(_2) -> bb6;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
 +     }
 + 
-+     bb6 (cleanup): {
-+         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
++     bb6: {
++         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++                                          // mir::Constant
++                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   }
   
index bd21405f14b3fcc663cbefef4caa0fb860c690d1..f27b64c305457a14b2da1b198d86a2b922980875 100644 (file)
@@ -7,7 +7,7 @@
       let mut _2: std::pin::Pin<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline_generator.rs:+1:14: +1:32
       let mut _3: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline_generator.rs:+1:23: +1:31
       let mut _4: [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline_generator.rs:+1:28: +1:31
-+     let mut _7: bool;                    // in scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++     let mut _7: bool;                    // in scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
       scope 1 {
           debug _r => _1;                  // in scope 1 at $DIR/inline_generator.rs:+1:9: +1:11
       }
@@ -23,7 +23,7 @@
 +             }
 +         }
 +     }
-+     scope 6 (inlined g::{closure#0}) {   // at $DIR/inline_generator.rs:9:14: 9:46
++     scope 6 (inlined g::{closure#0}) {   // at $DIR/inline_generator.rs:9:33: 9:46
 +         debug a => _7;                   // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7
 +         let mut _8: i32;                 // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39
 +         let mut _9: u32;                 // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
@@ -68,8 +68,8 @@
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline_generator.rs:9:33: 9:39
 -                                          // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
-+         StorageLive(_7);                 // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
-+         _7 = const false;                // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++         StorageLive(_7);                 // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
++         _7 = const false;                // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
 +         _10 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         _9 = discriminant((*_10));       // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         switchInt(move _9) -> [0: bb3, 1: bb8, 3: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
@@ -77,7 +77,7 @@
   
 -     bb3: {
 +     bb1: {
-+         StorageDead(_7);                 // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++         StorageDead(_7);                 // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46
           StorageDead(_2);                 // scope 0 at $DIR/inline_generator.rs:+1:45: +1:46
           StorageDead(_4);                 // scope 0 at $DIR/inline_generator.rs:+1:46: +1:47
           _0 = const ();                   // scope 0 at $DIR/inline_generator.rs:+0:11: +2:2
index 969573ba3253fcf1ed27fdb8b6fc64af8010e1de..09dd35c4c68b142af5c59ecf219ebcd5ce983aa9 100644 (file)
@@ -5,7 +5,7 @@
       debug f => _1;                       // in scope 0 at $DIR/inline_shims.rs:+0:20: +0:21
       let mut _0: fn(A, B);                // return place in scope 0 at $DIR/inline_shims.rs:+0:36: +0:44
       let mut _2: &fn(A, B);               // in scope 0 at $DIR/inline_shims.rs:+1:5: +1:14
-+     scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline_shims.rs:6:5: 6:14
++     scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline_shims.rs:6:7: 6:14
 +     }
   
       bb0: {
index 777681e1ce7ec4def0a6e72e6058bc4cac447fed..dc0c323504376c29edd7d43a6fbc65a2920f8b79 100644 (file)
@@ -6,7 +6,7 @@ fn a(_1: &mut [T]) -> &mut [T] {
     let mut _2: &mut [T];                // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
     let mut _3: &mut [T];                // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
     let mut _4: &mut [T];                // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
-    scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:3:5: 3:15
+    scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:3:7: 3:15
         debug self => _4;                // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
         let mut _5: &mut [T];            // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
     }
index 83545c991000e8e6bb3bbf52c003064e39122f9e..b6aff30149fadb32815e43ffb0e356e0756a496a 100644 (file)
@@ -6,7 +6,7 @@ fn b(_1: &mut Box<T>) -> &mut T {
     let mut _2: &mut T;                  // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
     let mut _3: &mut T;                  // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
     let mut _4: &mut std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
-    scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:8:5: 8:15
+    scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:8:7: 8:15
         debug self => _4;                // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         let mut _5: &mut T;              // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         let mut _6: &mut T;              // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
index ed4e9927ce9cdd6db0f913e2c7ae6c05b5eec8a2..af830d2494e61f9954a2b6129366fa2698b55f93 100644 (file)
@@ -5,7 +5,7 @@ fn c(_1: &[T]) -> &[T] {
     let mut _0: &[T];                    // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:25: +0:29
     let _2: &[T];                        // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
     let mut _3: &[T];                    // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
-    scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:13:5: 13:15
+    scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:13:7: 13:15
         debug self => _3;                // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
     }
 
index 18a2670be215886dcd7a81bcef28bfc0cffa74f8..4f9342247d70e8c611bb124b1bdd40f4e7fb3569 100644 (file)
@@ -5,7 +5,7 @@ fn d(_1: &Box<T>) -> &T {
     let mut _0: &T;                      // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:28: +0:30
     let _2: &T;                          // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
     let mut _3: &std::boxed::Box<T>;     // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
-    scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:18:5: 18:15
+    scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:18:7: 18:15
         debug self => _3;                // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         let mut _4: std::boxed::Box<T>;  // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
         let mut _5: *const T;            // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
index 8fe60a0245d7dcdf86c69fc37ad2a1e763c9d24d..b2706e5a436e2f02ae3084d8a75cb49b68a2c563 100644 (file)
@@ -23,7 +23,7 @@
               debug out => _4;             // in scope 2 at $DIR/issue_101973.rs:6:9: 6:16
           }
       }
-      scope 3 (inlined core::num::<impl u32>::rotate_right) { // at $DIR/issue_101973.rs:14:5: 14:58
+      scope 3 (inlined core::num::<impl u32>::rotate_right) { // at $DIR/issue_101973.rs:14:18: 14:58
           debug self => _4;                // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
           debug n => _6;                   // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
           let mut _15: u32;                // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
index 17b81633991fec12dfa7ead2aa8edb71d8080e89..bf3bcfdb5944266469c7ac301f05337fbd97b776 100644 (file)
@@ -7,41 +7,36 @@
       let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
       let mut _3: isize;                   // in scope 0 at $DIR/issue_73223.rs:+2:9: +2:16
       let _4: i32;                         // in scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
-      let mut _5: !;                       // in scope 0 at $DIR/issue_73223.rs:+3:17: +3:23
-      let mut _7: i32;                     // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27
-      let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _12: i32;                        // in scope 0 at $DIR/issue_73223.rs:+7:23: +7:24
-      let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _18: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _19: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _23: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _24: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _6: i32;                     // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27
+      let mut _7: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _8: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _11: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _13: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _14: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _16: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _18: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _19: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _20: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _21: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _22: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _24: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _25: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _26: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _27: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _29: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _30: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       scope 1 {
           debug split => _1;               // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14
-          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
+          let _5: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
           scope 3 {
-              debug _prev => _6;           // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14
-              let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _28: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              debug _prev => _5;           // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14
+              let _9: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              let _10: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              let mut _23: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               scope 4 {
-                  debug left_val => _13;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _14;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug left_val => _9;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug right_val => _10;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  let _15: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug kind => _20;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug kind => _15;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   }
               }
           }
@@ -61,7 +56,6 @@
       }
   
       bb1: {
-          nop;                             // scope 0 at $DIR/issue_73223.rs:+3:17: +3:23
           StorageDead(_2);                 // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
           StorageDead(_1);                 // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
           return;                          // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
           _1 = _4;                         // scope 2 at $DIR/issue_73223.rs:+2:20: +2:21
           StorageDead(_4);                 // scope 0 at $DIR/issue_73223.rs:+2:20: +2:21
           StorageDead(_2);                 // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
-          StorageLive(_6);                 // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
-          StorageLive(_7);                 // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
-          _7 = _1;                         // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
-          Deinit(_6);                      // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
-          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
-          discriminant(_6) = 1;            // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
-          StorageDead(_7);                 // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
+          StorageLive(_5);                 // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
+          StorageLive(_6);                 // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
+          _6 = _1;                         // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
+          Deinit(_5);                      // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+          ((_5 as Some).0: i32) = move _6; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+          discriminant(_5) = 1;            // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+          StorageDead(_6);                 // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
+          StorageLive(_24);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_25);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _7 = &_1;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_29);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_30);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = &_1;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _28 = const _;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _23 = const _;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_29);                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_30);                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _29 = move _10;                  // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _30 = move _11;                  // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _13 = _29;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = _30;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _15) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _8 = _23;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_24);                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_25);                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _24 = move _7;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _25 = move _8;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _9 = _24;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _10 = _25;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_13);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _13 = (*_9);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_14);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _14 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _12 = Eq(move _13, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_14);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_13);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _11 = Not(move _12);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(move _11) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb4: {
-          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_15);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          discriminant(_15) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_16);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_17);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _17 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-          StorageLive(_23);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_24);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = _13;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = _24;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_25);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_26);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_19);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _19 = _9;                        // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _18 = _19;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_20);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _21 = _10;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _20 = _21;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_22);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          discriminant(_22) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _16 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _18, move _20, move _22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a i32, &'b i32, Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
       }
   
       bb5: {
-          nop;                             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_29);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_30);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          nop;                             // scope 0 at $DIR/issue_73223.rs:+0:11: +8:2
-          StorageDead(_6);                 // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
+          StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_24);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_25);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_5);                 // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
           StorageDead(_1);                 // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
           return;                          // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
       }
index e97b46f6ecc82b19b29ccddcdd162afb07801192..c24543daeacb7939e50261e7f38a4ba7dab1e932 100644 (file)
       let mut _6: T;                       // in scope 0 at $DIR/issue_76432.rs:+1:21: +1:22
       let mut _7: T;                       // in scope 0 at $DIR/issue_76432.rs:+1:24: +1:25
       let mut _8: T;                       // in scope 0 at $DIR/issue_76432.rs:+1:27: +1:28
-      let _9: [*const T; 3];               // in scope 0 at $DIR/issue_76432.rs:+2:5: +5:6
+      let mut _9: usize;                   // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
       let mut _10: usize;                  // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
-      let mut _11: usize;                  // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
-      let mut _12: bool;                   // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
-      let mut _16: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:38: +3:52
-      let mut _17: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:38: +3:52
-      let mut _18: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:54: +3:68
-      let mut _19: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:54: +3:68
-      let mut _20: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84
-      let mut _21: *const T;               // in scope 0 at $DIR/issue_76432.rs:+3:70: +3:84
-      let mut _22: !;                      // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
+      let mut _11: bool;                   // in scope 0 at $DIR/issue_76432.rs:+3:9: +3:33
+      let mut _15: !;                      // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
       scope 1 {
           debug v => _2;                   // in scope 1 at $DIR/issue_76432.rs:+1:9: +1:10
-          let _13: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
-          let _14: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
-          let _15: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
+          let _12: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
+          let _13: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
+          let _14: &T;                     // in scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
           scope 2 {
-              debug v1 => _13;             // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16
-              debug v2 => _14;             // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24
-              debug v3 => _15;             // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32
+              debug v1 => _12;             // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16
+              debug v2 => _13;             // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24
+              debug v3 => _14;             // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32
           }
       }
   
           _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29
           StorageDead(_3);                 // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29
           StorageDead(_4);                 // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30
-          StorageLive(_9);                 // scope 1 at $DIR/issue_76432.rs:+2:5: +5:6
-          _10 = Len((*_2));                // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-          _11 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
--         _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
--         switchInt(move _12) -> [0: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+          _9 = Len((*_2));                 // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+          _10 = const 3_usize;             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+-         _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
+-         switchInt(move _11) -> [0: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
 +         nop;                             // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
-+         switchInt(move _10) -> [3: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
++         switchInt(move _9) -> [3: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33
       }
   
       bb1: {
-          StorageLive(_22);                // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
-          _22 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
+          StorageLive(_15);                // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
+          _15 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/panic.rs:LL:COL
                                            // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(<ZST>) }
       }
   
       bb2: {
-          StorageLive(_13);                // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
-          _13 = &(*_2)[0 of 3];            // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
-          StorageLive(_14);                // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
-          _14 = &(*_2)[1 of 3];            // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
-          StorageLive(_15);                // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
-          _15 = &(*_2)[2 of 3];            // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
-          StorageLive(_16);                // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52
-          StorageLive(_17);                // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52
-          _17 = &raw const (*_13);         // scope 2 at $DIR/issue_76432.rs:+3:38: +3:40
-          _16 = _17;                       // scope 2 at $DIR/issue_76432.rs:+3:38: +3:52
-          StorageLive(_18);                // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68
-          StorageLive(_19);                // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68
-          _19 = &raw const (*_14);         // scope 2 at $DIR/issue_76432.rs:+3:54: +3:56
-          _18 = _19;                       // scope 2 at $DIR/issue_76432.rs:+3:54: +3:68
-          StorageLive(_20);                // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84
-          StorageLive(_21);                // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84
-          _21 = &raw const (*_15);         // scope 2 at $DIR/issue_76432.rs:+3:70: +3:72
-          _20 = _21;                       // scope 2 at $DIR/issue_76432.rs:+3:70: +3:84
-          _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:+3:37: +3:85
-          StorageDead(_21);                // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_20);                // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_19);                // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_18);                // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_17);                // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_16);                // scope 2 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_15);                // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
+          StorageLive(_12);                // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
+          _12 = &(*_2)[0 of 3];            // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16
+          StorageLive(_13);                // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
+          _13 = &(*_2)[1 of 3];            // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24
+          StorageLive(_14);                // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
+          _14 = &(*_2)[2 of 3];            // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32
           StorageDead(_14);                // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
           StorageDead(_13);                // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
-          StorageDead(_9);                 // scope 1 at $DIR/issue_76432.rs:+5:6: +5:7
-          nop;                             // scope 0 at $DIR/issue_76432.rs:+0:44: +6:2
+          StorageDead(_12);                // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85
           StorageDead(_5);                 // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2
           StorageDead(_2);                 // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/issue_76432.rs:+6:2: +6:2
index e0d6b58f229c4a63be620ad3d46b16ac70629b9e..c17d221f86a84a43f096f8cab92d58852e875cd7 100644 (file)
@@ -4,9 +4,9 @@ fn num_to_digit(_1: char) -> u32 {
     debug num => _1;                     // in scope 0 at $DIR/issue_59352.rs:+0:21: +0:24
     let mut _0: u32;                     // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38
     let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
-    let mut _3: u32;                     // in scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+    let mut _3: u32;                     // in scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
     let mut _9: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-    scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:14:8: 14:23
+    scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:14:12: 14:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         debug radix => _3;               // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         let mut _4: &std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
@@ -16,7 +16,7 @@ fn num_to_digit(_1: char) -> u32 {
             debug self => _4;            // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
         }
     }
-    scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:14:26: 14:50
+    scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:14:42: 14:50
         debug self => _2;                // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         let mut _7: isize;               // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         let mut _8: !;                   // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
@@ -26,7 +26,7 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb0: {
-        StorageLive(_3);                 // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+        StorageLive(_3);                 // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
         StorageLive(_4);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         StorageLive(_5);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         StorageLive(_6);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
@@ -65,7 +65,7 @@ fn num_to_digit(_1: char) -> u32 {
         _9 = discriminant((*_4));        // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
         StorageDead(_4);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         StorageDead(_5);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
-        StorageDead(_3);                 // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+        StorageDead(_3);                 // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
         switchInt(move _9) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
     }
 
index 6ae16bdb5b88a6b673807d83b9a32fedf2c0b6c6..e57544e09e2a0f6a137240c628ad852ebeff31a3 100644 (file)
@@ -22,6 +22,9 @@
                   let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                   scope 9 {
                       debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
+                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                      }
                   }
               }
           }
           StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
--         _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-+         _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/result.rs:LL:COL
-                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
+          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
       }
   
 -     bb5: {
 +         _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
       }
-  
--     bb8: {
-+     bb7: {
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..916f990
--- /dev/null
@@ -0,0 +1,52 @@
+// MIR for `ezmap` after PreCodegen
+
+fn ezmap(_1: Option<i32>) -> Option<i32> {
+    debug x => _1;                       // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
+    let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
+    let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+    scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
+        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 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
+            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
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+        _3 = discriminant(_1);           // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+        switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
+    }
+
+    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
+        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+    }
+
+    bb2: {
+        unreachable;                     // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+    }
+
+    bb3: {
+        _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        StorageLive(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        _4 = Add(move _5, const 1_i32);  // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        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
+        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
+    }
+
+    bb4: {
+        StorageDead(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
+        return;                          // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/simple_option_map_e2e.rs b/src/test/mir-opt/simple_option_map_e2e.rs
new file mode 100644 (file)
index 0000000..2acd2a2
--- /dev/null
@@ -0,0 +1,19 @@
+#[inline(always)]
+fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
+where
+    F: FnOnce(T) -> U,
+{
+    match slf {
+        Some(x) => Some(f(x)),
+        None => None,
+    }
+}
+
+// EMIT_MIR simple_option_map_e2e.ezmap.PreCodegen.after.mir
+pub fn ezmap(x: Option<i32>) -> Option<i32> {
+    map(x, |n| n + 1)
+}
+
+fn main() {
+    assert_eq!(None, ezmap(None));
+}
index aea0114744352d0b7a2af771f2cdc8db318a670d..f9e22866bee9947be9243c53747709f596015dc8 100644 (file)
   
       bb2: {
           StorageDead(_2);                 // scope 0 at $DIR/simplify_if.rs:+2:15: +2:16
-          nop;                             // scope 0 at $DIR/simplify_if.rs:+1:14: +3:6
           goto -> bb4;                     // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6
       }
   
       bb3: {
-          nop;                             // scope 0 at $DIR/simplify_if.rs:+3:6: +3:6
           goto -> bb4;                     // scope 0 at $DIR/simplify_if.rs:+1:5: +3:6
       }
   
diff --git a/src/test/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..1be27e9
--- /dev/null
@@ -0,0 +1,33 @@
+- // MIR for `c` before SimplifyLocals-before-const-prop
++ // MIR for `c` after SimplifyLocals-before-const-prop
+  
+  fn c() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
+      let _1: [u8; 10];                    // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+-     let mut _2: &[u8];                   // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+-     let mut _3: &[u8; 10];               // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+-     let _4: &[u8; 10];                   // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+      scope 1 {
+          debug bytes => _1;               // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
+          scope 2 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+          _1 = [const 0_u8; 10];           // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:26
+-         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+-         StorageLive(_3);                 // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+-         StorageLive(_4);                 // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+-         _4 = &_1;                        // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+-         _3 = &(*_4);                     // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+-         _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+-         StorageDead(_3);                 // scope 1 at $DIR/simplify_locals.rs:+3:25: +3:26
+-         StorageDead(_4);                 // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
+-         StorageDead(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
+          _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:8: +4:2
+          StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/simplify_locals.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.c.SimplifyLocals.diff
deleted file mode 100644 (file)
index 1a5143a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-- // MIR for `c` before SimplifyLocals
-+ // MIR for `c` after SimplifyLocals
-  
-  fn c() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
-      let _1: [u8; 10];                    // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
--     let mut _2: &[u8];                   // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
--     let mut _3: &[u8; 10];               // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
--     let _4: &[u8; 10];                   // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
-      scope 1 {
-          debug bytes => _1;               // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
-          scope 2 {
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
-          _1 = [const 0_u8; 10];           // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:26
--         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
--         StorageLive(_3);                 // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
--         StorageLive(_4);                 // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
--         _4 = &_1;                        // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
--         _3 = &(*_4);                     // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
--         _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
--         StorageDead(_3);                 // scope 1 at $DIR/simplify_locals.rs:+3:25: +3:26
--         StorageDead(_4);                 // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
--         StorageDead(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
-          _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:8: +4:2
-          StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+4:1: +4:2
-          return;                          // scope 0 at $DIR/simplify_locals.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.d1.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.d1.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..9817380
--- /dev/null
@@ -0,0 +1,19 @@
+- // MIR for `d1` before SimplifyLocals-before-const-prop
++ // MIR for `d1` after SimplifyLocals-before-const-prop
+  
+  fn d1() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+-     let mut _1: E;                       // in scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+      scope 1 {
+      }
+  
+      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
+-         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
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff
deleted file mode 100644 (file)
index 6426bf9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-- // MIR for `d1` before SimplifyLocals
-+ // MIR for `d1` after SimplifyLocals
-  
-  fn d1() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
--     let mut _1: E;                       // in scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
-      scope 1 {
-      }
-  
-      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
--         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
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.d2.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.d2.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..b152dc8
--- /dev/null
@@ -0,0 +1,29 @@
+- // MIR for `d2` before SimplifyLocals-before-const-prop
++ // MIR for `d2` after SimplifyLocals-before-const-prop
+  
+  fn d2() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+-     let mut _1: E;                       // in scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+-     let mut _2: (i32, E);                // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+-     let mut _3: E;                       // in scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+  
+      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
+-         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
+-         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
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:26: +2:27
+          _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
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff
deleted file mode 100644 (file)
index db5ab18..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-- // MIR for `d2` before SimplifyLocals
-+ // MIR for `d2` after SimplifyLocals
-  
-  fn d2() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
--     let mut _1: E;                       // in scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
--     let mut _2: (i32, E);                // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
--     let mut _3: E;                       // in scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
-  
-      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
--         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
--         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
--         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:26: +2:27
-          _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
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..9ca1dbb
--- /dev/null
@@ -0,0 +1,21 @@
+- // MIR for `expose_addr` before SimplifyLocals-before-const-prop
++ // MIR for `expose_addr` after SimplifyLocals-before-const-prop
+  
+  fn expose_addr(_1: *const usize) -> () {
+      debug p => _1;                       // in scope 0 at $DIR/simplify_locals.rs:+0:16: +0:17
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:33: +0:33
+      let _2: usize;                       // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+      let mut _3: *const usize;            // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+          StorageLive(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+          _3 = _1;                         // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
+          _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:33: +3:2
+          return;                          // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff
deleted file mode 100644 (file)
index c707b0d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `expose_addr` before SimplifyLocals
-+ // MIR for `expose_addr` after SimplifyLocals
-  
-  fn expose_addr(_1: *const usize) -> () {
-      debug p => _1;                       // in scope 0 at $DIR/simplify_locals.rs:+0:16: +0:17
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:33: +0:33
-      let _2: usize;                       // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
-      let mut _3: *const usize;            // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
-          StorageLive(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
-          _3 = _1;                         // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
-          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
-          StorageDead(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
-          _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:33: +3:2
-          return;                          // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.r.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.r.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..19dacb4
--- /dev/null
@@ -0,0 +1,31 @@
+- // MIR for `r` before SimplifyLocals-before-const-prop
++ // MIR for `r` after SimplifyLocals-before-const-prop
+  
+  fn r() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
+      let mut _1: i32;                     // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+-     let mut _2: &i32;                    // in scope 0 at $DIR/simplify_locals.rs:+3:13: +3:15
+-     let mut _3: &mut i32;                // in scope 0 at $DIR/simplify_locals.rs:+4:13: +4:19
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
+          scope 2 {
+              scope 3 {
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+          _1 = const 1_i32;                // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:18
+-         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
+-         _2 = &_1;                        // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
+-         StorageDead(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:15: +3:16
+-         StorageLive(_3);                 // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
+-         _3 = &mut _1;                    // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
+-         StorageDead(_3);                 // scope 2 at $DIR/simplify_locals.rs:+4:19: +4:20
+          _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:8: +5:2
+          StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/simplify_locals.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.r.SimplifyLocals.diff
deleted file mode 100644 (file)
index ff6eb2c..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-- // MIR for `r` before SimplifyLocals
-+ // MIR for `r` after SimplifyLocals
-  
-  fn r() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
-      let mut _1: i32;                     // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
--     let mut _2: &i32;                    // in scope 0 at $DIR/simplify_locals.rs:+3:13: +3:15
--     let mut _3: &mut i32;                // in scope 0 at $DIR/simplify_locals.rs:+4:13: +4:19
-      scope 1 {
-          debug a => _1;                   // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
-          scope 2 {
-              scope 3 {
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
-          _1 = const 1_i32;                // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:18
--         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
--         _2 = &_1;                        // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
--         StorageDead(_2);                 // scope 1 at $DIR/simplify_locals.rs:+3:15: +3:16
--         StorageLive(_3);                 // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
--         _3 = &mut _1;                    // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
--         StorageDead(_3);                 // scope 2 at $DIR/simplify_locals.rs:+4:19: +4:20
-          _0 = const ();                   // scope 0 at $DIR/simplify_locals.rs:+0:8: +5:2
-          StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+5:1: +5:2
-          return;                          // scope 0 at $DIR/simplify_locals.rs:+5:2: +5:2
-      }
-  }
-  
index 89d9391f832dc3e5290eeab56719aca61c268f72..7bbc0481c68a49a8010d1c228423a6cc413df2f6 100644 (file)
@@ -1,4 +1,4 @@
-// unit-test: SimplifyLocals
+// unit-test: SimplifyLocals-before-const-prop
 
 
 #![feature(thread_local)]
@@ -9,26 +9,26 @@ enum E {
      B,
 }
 
-// EMIT_MIR simplify_locals.c.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.c.SimplifyLocals-before-const-prop.diff
 fn c() {
     let bytes = [0u8; 10];
     // Unused cast
     let _: &[u8] = &bytes;
 }
 
-// EMIT_MIR simplify_locals.d1.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.d1.SimplifyLocals-before-const-prop.diff
 fn d1() {
     // Unused set discriminant
     let _ = E::A;
 }
 
-// EMIT_MIR simplify_locals.d2.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.d2.SimplifyLocals-before-const-prop.diff
 fn d2() {
     // Unused set discriminant
     {(10, E::A)}.1 = E::B;
 }
 
-// EMIT_MIR simplify_locals.r.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.r.SimplifyLocals-before-const-prop.diff
 fn r() {
     let mut a = 1;
     // Unused references
@@ -38,31 +38,31 @@ fn r() {
 
 #[thread_local] static mut X: u32 = 0;
 
-// EMIT_MIR simplify_locals.t1.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t1.SimplifyLocals-before-const-prop.diff
 fn t1() {
     // Unused thread local
     unsafe { X };
 }
 
-// EMIT_MIR simplify_locals.t2.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t2.SimplifyLocals-before-const-prop.diff
 fn t2() {
     // Unused thread local
     unsafe { &mut X };
 }
 
-// EMIT_MIR simplify_locals.t3.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t3.SimplifyLocals-before-const-prop.diff
 fn t3() {
     // Unused thread local
     unsafe { *&mut X };
 }
 
-// EMIT_MIR simplify_locals.t4.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.t4.SimplifyLocals-before-const-prop.diff
 fn t4() -> u32 {
     // Used thread local
     unsafe { X + 1 }
 }
 
-// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
+// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
 fn expose_addr(p: *const usize) {
     // Used pointer to address cast. Has a side effect of exposing the provenance.
     p as usize;
diff --git a/src/test/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.t1.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..1b2e115
--- /dev/null
@@ -0,0 +1,22 @@
+- // MIR for `t1` before SimplifyLocals-before-const-prop
++ // MIR for `t1` after SimplifyLocals-before-const-prop
+  
+  fn t1() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+-     let _1: u32;                         // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+-     let mut _2: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+      scope 1 {
+      }
+  
+      bb0: {
+-         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+-         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+-         _2 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+-         _1 = (*_2);                      // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+-         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
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t1.SimplifyLocals.diff
deleted file mode 100644 (file)
index 49db774..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `t1` before SimplifyLocals
-+ // MIR for `t1` after SimplifyLocals
-  
-  fn t1() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
--     let _1: u32;                         // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
--     let mut _2: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
-      scope 1 {
-      }
-  
-      bb0: {
--         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
--         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
--         _2 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
--         _1 = (*_2);                      // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
--         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
--         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
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.t2.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..cf01935
--- /dev/null
@@ -0,0 +1,22 @@
+- // MIR for `t2` before SimplifyLocals-before-const-prop
++ // MIR for `t2` after SimplifyLocals-before-const-prop
+  
+  fn t2() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+-     let _1: &mut u32;                    // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:20
+-     let mut _2: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:19: +2:20
+      scope 1 {
+      }
+  
+      bb0: {
+-         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:22
+-         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
+-         _2 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
+-         _1 = &mut (*_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:20
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
+-         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
+          _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
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t2.SimplifyLocals.diff
deleted file mode 100644 (file)
index e3f4ae3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `t2` before SimplifyLocals
-+ // MIR for `t2` after SimplifyLocals
-  
-  fn t2() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
--     let _1: &mut u32;                    // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:20
--     let mut _2: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:19: +2:20
-      scope 1 {
-      }
-  
-      bb0: {
--         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:22
--         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
--         _2 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
--         _1 = &mut (*_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:20
--         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
--         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
-          _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
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.t3.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..90ee215
--- /dev/null
@@ -0,0 +1,26 @@
+- // MIR for `t3` before SimplifyLocals-before-const-prop
++ // MIR for `t3` after SimplifyLocals-before-const-prop
+  
+  fn t3() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+-     let _1: u32;                         // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:21
+-     let mut _2: &mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:15: +2:21
+-     let mut _3: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:20: +2:21
+      scope 1 {
+      }
+  
+      bb0: {
+-         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:23
+-         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
+-         StorageLive(_3);                 // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
+-         _3 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
+-         _2 = &mut (*_3);                 // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
+-         _1 = (*_2);                      // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:21
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+-         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+          _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
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t3.SimplifyLocals.diff
deleted file mode 100644 (file)
index f1ce777..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-- // MIR for `t3` before SimplifyLocals
-+ // MIR for `t3` after SimplifyLocals
-  
-  fn t3() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
--     let _1: u32;                         // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:21
--     let mut _2: &mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:15: +2:21
--     let mut _3: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:20: +2:21
-      scope 1 {
-      }
-  
-      bb0: {
--         StorageLive(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:23
--         StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
--         StorageLive(_3);                 // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
--         _3 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
--         _2 = &mut (*_3);                 // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
--         _1 = (*_2);                      // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:21
--         StorageDead(_3);                 // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
--         StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
--         StorageDead(_1);                 // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
-          _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
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals.t4.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..9add9a6
--- /dev/null
@@ -0,0 +1,22 @@
+- // MIR for `t4` before SimplifyLocals-before-const-prop
++ // MIR for `t4` after SimplifyLocals-before-const-prop
+  
+  fn t4() -> u32 {
+      let mut _0: u32;                     // return place in scope 0 at $DIR/simplify_locals.rs:+0:12: +0:15
+      let mut _1: u32;                     // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+      let mut _2: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+          StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+          _2 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+          _1 = (*_2);                      // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+          _0 = Add(move _1, const 1_u32);  // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:19
+          StorageDead(_1);                 // scope 1 at $DIR/simplify_locals.rs:+2:18: +2:19
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+3:1: +3:2
+          return;                          // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.t4.SimplifyLocals.diff
deleted file mode 100644 (file)
index 71cf959..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `t4` before SimplifyLocals
-+ // MIR for `t4` after SimplifyLocals
-  
-  fn t4() -> u32 {
-      let mut _0: u32;                     // return place in scope 0 at $DIR/simplify_locals.rs:+0:12: +0:15
-      let mut _1: u32;                     // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
-      let mut _2: *mut u32;                // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
-      scope 1 {
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-          StorageLive(_2);                 // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-          _2 = &/*tls*/ mut X;             // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-          _1 = (*_2);                      // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
-          _0 = Add(move _1, const 1_u32);  // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:19
-          StorageDead(_1);                 // scope 1 at $DIR/simplify_locals.rs:+2:18: +2:19
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_locals.rs:+3:1: +3:2
-          return;                          // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
new file mode 100644 (file)
index 0000000..f888c62
--- /dev/null
@@ -0,0 +1,62 @@
+- // MIR for `foo` before SimplifyLocals-final
++ // MIR for `foo` after SimplifyLocals-final
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+0:13: +0:13
+      let mut _1: (std::option::Option<u8>, std::option::Option<T>); // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+      let mut _2: std::option::Option<u8>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+      let mut _3: std::option::Option<T>;  // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+      let mut _4: isize;                   // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20
+-     let mut _7: bool;                    // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+-     let mut _8: u8;                      // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+      scope 1 {
+          debug a => _6;                   // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+          let _6: u8;                      // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+      }
+  
+      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
+          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
+          StorageDead(_3);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
+          StorageDead(_2);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
+          _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+          switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+      }
+  
+      bb1: {
+          _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+          switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+      }
+  
+      bb2: {
+          StorageLive(_6);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+          _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+-         StorageLive(_7);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+-         StorageLive(_8);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+-         _8 = _6;                         // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+-         _7 = Gt(move _8, const 42_u8);   // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+-         StorageDead(_8);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:19: +2:20
+-         StorageDead(_7);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10
+          StorageDead(_6);                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6
+          goto -> bb3;                     // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6
+      }
+  
+      bb3: {
+          drop(_1) -> bb4;                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
+      }
+  
+      bb4: {
+          StorageDead(_1);                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
deleted file mode 100644 (file)
index a2b5522..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-- // MIR for `foo` before SimplifyLocals
-+ // MIR for `foo` after SimplifyLocals
-  
-  fn foo() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+0:13: +0:13
-      let mut _1: (std::option::Option<u8>, std::option::Option<T>); // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
-      let mut _2: std::option::Option<u8>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
-      let mut _3: std::option::Option<T>;  // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
-      let mut _4: isize;                   // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20
--     let mut _7: bool;                    // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
--     let mut _8: u8;                      // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
-      scope 1 {
-          debug a => _6;                   // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
-          let _6: u8;                      // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
-      }
-  
-      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
-          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
-          StorageDead(_3);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
-          StorageDead(_2);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
-          _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
-          switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
-      }
-  
-      bb1: {
-          _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
-          switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
-      }
-  
-      bb2: {
-          StorageLive(_6);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
-          _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
--         StorageLive(_7);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
--         StorageLive(_8);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
--         _8 = _6;                         // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
--         _7 = Gt(move _8, const 42_u8);   // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
--         StorageDead(_8);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:19: +2:20
--         StorageDead(_7);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10
-          StorageDead(_6);                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6
-          goto -> bb3;                     // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6
-      }
-  
-      bb3: {
-          drop(_1) -> bb4;                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
-      }
-  
-      bb4: {
-          StorageDead(_1);                 // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:2: +6:2
-      }
-  }
-  
index 78b1f9f55e59d2a8119077cf6e837266ed76ddd9..1fdba6e99e3ede935872c9e9af7c058e29a2a358 100644 (file)
@@ -12,4 +12,4 @@ fn main() {
     foo::<()>();
 }
 
-// EMIT_MIR simplify_locals_fixedpoint.foo.SimplifyLocals.diff
+// EMIT_MIR simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..efb2b09
--- /dev/null
@@ -0,0 +1,109 @@
+- // MIR for `main` before SimplifyLocals-before-const-prop
++ // MIR for `main` after SimplifyLocals-before-const-prop
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +0:11
+-     let mut _1: ((), ());                // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+-     let mut _2: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+-     let mut _3: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+-     let _4: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
+-     let mut _5: ((), ());                // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+-     let mut _6: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+-     let mut _7: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+-     let _8: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+-     let mut _9: u8;                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+-     let mut _10: u8;                     // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+-     let mut _11: Temp;                   // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++     let _1: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++     let mut _2: ((), ());                // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++     let mut _3: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++     let mut _4: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++     let _5: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++     let mut _6: u8;                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++     let mut _7: u8;                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++     let mut _8: Temp;                    // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+      scope 1 {
+      }
+  
+      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
+-         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
+-         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
+-         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
+-         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
++         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
++         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
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:15:5: 15:12
+                                           // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+-         StorageDead(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
+-         StorageDead(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
+-         StorageLive(_8);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+-         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
+-         _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
+-         _8 = use_u8(move _9) -> bb2;     // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++         StorageDead(_2);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
++         StorageDead(_1);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
++         StorageLive(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++         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
++         _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
++         _5 = use_u8(move _6) -> bb2;     // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:17:5: 17:11
+                                           // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+-         StorageDead(_9);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
+-         StorageDead(_11);                // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
++         StorageDead(_6);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
+          StorageDead(_8);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
++         StorageDead(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
+          _0 = const ();                   // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +5:2
+          return;                          // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
deleted file mode 100644 (file)
index 7827227..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-- // MIR for `main` before SimplifyLocals
-+ // MIR for `main` after SimplifyLocals
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +0:11
--     let mut _1: ((), ());                // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
--     let mut _2: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
--     let mut _3: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
--     let _4: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
--     let mut _5: ((), ());                // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
--     let mut _6: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
--     let mut _7: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
--     let _8: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
--     let mut _9: u8;                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
--     let mut _10: u8;                     // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
--     let mut _11: Temp;                   // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-+     let _1: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
-+     let mut _2: ((), ());                // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
-+     let mut _3: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
-+     let mut _4: ();                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
-+     let _5: ();                          // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-+     let mut _6: u8;                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
-+     let mut _7: u8;                      // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
-+     let mut _8: Temp;                    // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
-      scope 1 {
-      }
-  
-      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
--         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
--         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
--         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
--         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
-+         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
-+         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
-                                           // mir::Constant
-                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:15:5: 15:12
-                                           // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
-      }
-  
-      bb1: {
--         StorageDead(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
--         StorageDead(_4);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
--         StorageLive(_8);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
--         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
--         _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
--         _8 = use_u8(move _9) -> bb2;     // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-+         StorageDead(_2);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
-+         StorageDead(_1);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
-+         StorageLive(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-+         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
-+         _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
-+         _5 = use_u8(move _6) -> bb2;     // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
-                                           // mir::Constant
-                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:17:5: 17:11
-                                           // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
-      }
-  
-      bb2: {
--         StorageDead(_9);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
--         StorageDead(_11);                // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
-+         StorageDead(_6);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
-          StorageDead(_8);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
-+         StorageDead(_5);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
-          _0 = const ();                   // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +5:2
-          return;                          // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+5:2: +5:2
-      }
-  }
-  
index 39b7911d4aedbcfafd6fd3a4c38ed43f92a189f9..7a03a2837ae7ffdf59c21495871f4774e007a6ca 100644 (file)
@@ -1,4 +1,4 @@
-// unit-test: SimplifyLocals
+// unit-test: SimplifyLocals-before-const-prop
 // compile-flags: -C overflow-checks=no
 
 fn use_zst(_: ((), ())) {}
@@ -9,7 +9,7 @@ struct Temp {
 
 fn use_u8(_: u8) {}
 
-// EMIT_MIR simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+// EMIT_MIR simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
 fn main() {
     let ((), ()) = ((), ());
     use_zst(((), ()));
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff
new file mode 100644 (file)
index 0000000..027c983
--- /dev/null
@@ -0,0 +1,52 @@
+- // MIR for `map` before SimplifyLocals-before-const-prop
++ // MIR for `map` after SimplifyLocals-before-const-prop
+  
+  fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
+      debug x => _1;                       // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:8: +0:9
+      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:31: +0:46
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:9: +2:13
+      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+      let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+-     let mut _5: bool;                    // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+-     let mut _6: isize;                   // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+-     let mut _7: isize;                   // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+      }
+  
+      bb0: {
+-         _5 = const false;                // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+-         _5 = const true;                 // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+          switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:5: +1:12
+      }
+  
+      bb1: {
+          StorageLive(_3);                 // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+          _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
+          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
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+      }
+  
+      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
+          goto -> bb4;                     // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+      }
+  
+      bb4: {
+-         _6 = discriminant(_1);           // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
deleted file mode 100644 (file)
index 9ec138d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-  
-  fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:8: +0:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:31: +0:46
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:9: +2:13
-      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
-      let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
--     let mut _5: bool;                    // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
--     let mut _7: isize;                   // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
-      }
-  
-      bb0: {
--         _5 = const false;                // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
--         _5 = const true;                 // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
-          switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
-          _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
-          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
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
-      }
-  
-      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
-          goto -> bb4;                     // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
-      }
-  
-      bb4: {
--         _6 = discriminant(_1);           // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
-          return;                          // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:2: +5:2
-      }
-  }
-  
index d09bd92c4e81d176328a1159f1c23aadd8c1e723..de65857412cfc7a422194a4956461295349b4c6f 100644 (file)
@@ -1,4 +1,4 @@
-// unit-test: SimplifyLocals
+// unit-test: SimplifyLocals-before-const-prop
 
 fn map(x: Option<Box<()>>) -> Option<Box<()>> {
     match x {
@@ -11,4 +11,4 @@ fn main() {
     map(None);
 }
 
-// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
+// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff
index f00ac5716a7517c7b29f56dc48688ca8ee37784e..70bfbf1b3e366473e3dd9fed7c2e3c0500a84790 100644 (file)
@@ -21,7 +21,6 @@
       }
   
       bb1: {
-          nop;                             // scope 0 at $DIR/simplify_match.rs:+3:18: +3:20
           goto -> bb3;                     // scope 0 at $DIR/simplify_match.rs:+3:18: +3:20
       }
   
diff --git a/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
new file mode 100644 (file)
index 0000000..b4fb330
--- /dev/null
@@ -0,0 +1,16 @@
+// MIR for `process_never` after SimplifyLocals-final
+
+fn process_never(_1: *const !) -> () {
+    debug input => _1;                   // in scope 0 at $DIR/uninhabited_enum.rs:+0:22: +0:27
+    let mut _0: ();                      // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:39: +0:39
+    let _2: &!;                          // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+    scope 1 {
+        debug _input => _2;              // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+    }
+    scope 2 {
+    }
+
+    bb0: {
+        unreachable;                     // scope 0 at $DIR/uninhabited_enum.rs:+0:39: +2:2
+    }
+}
diff --git a/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir
deleted file mode 100644 (file)
index 2c0fcc6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// MIR for `process_never` after SimplifyLocals
-
-fn process_never(_1: *const !) -> () {
-    debug input => _1;                   // in scope 0 at $DIR/uninhabited_enum.rs:+0:22: +0:27
-    let mut _0: ();                      // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:39: +0:39
-    let _2: &!;                          // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
-    scope 1 {
-        debug _input => _2;              // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
-    }
-    scope 2 {
-    }
-
-    bb0: {
-        unreachable;                     // scope 0 at $DIR/uninhabited_enum.rs:+0:39: +2:2
-    }
-}
diff --git a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
new file mode 100644 (file)
index 0000000..2af8649
--- /dev/null
@@ -0,0 +1,18 @@
+// MIR for `process_void` after SimplifyLocals-final
+
+fn process_void(_1: *const Void) -> () {
+    debug input => _1;                   // in scope 0 at $DIR/uninhabited_enum.rs:+0:21: +0:26
+    let mut _0: ();                      // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:41: +0:41
+    let _2: &Void;                       // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+    scope 1 {
+        debug _input => _2;              // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+    }
+    scope 2 {
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+        StorageDead(_2);                 // scope 0 at $DIR/uninhabited_enum.rs:+4:1: +4:2
+        return;                          // scope 0 at $DIR/uninhabited_enum.rs:+4:2: +4:2
+    }
+}
diff --git a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir
deleted file mode 100644 (file)
index ae341a7..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// MIR for `process_void` after SimplifyLocals
-
-fn process_void(_1: *const Void) -> () {
-    debug input => _1;                   // in scope 0 at $DIR/uninhabited_enum.rs:+0:21: +0:26
-    let mut _0: ();                      // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:41: +0:41
-    let _2: &Void;                       // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
-    scope 1 {
-        debug _input => _2;              // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
-    }
-    scope 2 {
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
-        StorageDead(_2);                 // scope 0 at $DIR/uninhabited_enum.rs:+4:1: +4:2
-        return;                          // scope 0 at $DIR/uninhabited_enum.rs:+4:2: +4:2
-    }
-}
index 97c6e8cd5311107d5e94d825981563af444c532a..19db548157a66742a63a97e77e580e62efc26c8d 100644 (file)
@@ -2,13 +2,13 @@
 
 pub enum Void {}
 
-// EMIT_MIR uninhabited_enum.process_never.SimplifyLocals.after.mir
+// EMIT_MIR uninhabited_enum.process_never.SimplifyLocals-final.after.mir
 #[no_mangle]
 pub fn process_never(input: *const !) {
    let _input = unsafe { &*input };
 }
 
-// EMIT_MIR uninhabited_enum.process_void.SimplifyLocals.after.mir
+// EMIT_MIR uninhabited_enum.process_void.SimplifyLocals-final.after.mir
 #[no_mangle]
 pub fn process_void(input: *const Void) {
    let _input = unsafe { &*input };
index 984ef476e10209d4e5f830ccabc9f1af04a989ef..bb1de59d4a73f0b2c059a85e312178a06ca585f1 100644 (file)
@@ -4,13 +4,8 @@
   fn change_loop_body() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
       let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
-      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
-      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
-      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
-      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
+      let mut _3: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
           scope 2 {
       bb0: {
           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(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          Deinit(_3);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          discriminant(_3) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
--         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          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
+-         _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
 +         switchInt(const 0_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          switchInt(((_2 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb2: {
           _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
-          nop;                             // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
           goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
       }
   
       bb3: {
-          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          nop;                             // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
           goto -> bb4;                     // scope 1 at no-location
       }
   
       bb4: {
-          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+          StorageDead(_2);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
           StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
       }
index 1556c240dc57a4335f848ca05289bff38cb366a6..b95d91b13dd7976c646481fc8425b4754b874095 100644 (file)
@@ -44,7 +44,7 @@ fn while_loop(_1: bool) -> () {
 
     bb5: {
         StorageDead(_4);                 // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
-        goto -> bb8;                     // scope 0 at no-location
+        goto -> bb7;                     // scope 0 at no-location
     }
 
     bb6: {
@@ -54,10 +54,6 @@ fn while_loop(_1: bool) -> () {
     }
 
     bb7: {
-        goto -> bb8;                     // scope 0 at no-location
-    }
-
-    bb8: {
         StorageDead(_2);                 // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
         return;                          // scope 0 at $DIR/while_storage.rs:+6:2: +6:2
     }
index 74aaabfbf1b4b5416f4f331c0d1da05b088fb0ec..384589de3b4807b789679eca7020edfdd3006ad1 100644 (file)
@@ -5,6 +5,11 @@
 extern crate rustc_graphviz;
 // A simple rust project
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 extern crate krate2;
 extern crate krate2 as krate3;
 
diff --git a/src/test/run-make/dump-mono-stats/Makefile b/src/test/run-make/dump-mono-stats/Makefile
new file mode 100644 (file)
index 0000000..fe1112f
--- /dev/null
@@ -0,0 +1,5 @@
+include ../../run-make-fulldeps/tools.mk
+
+all:
+       $(RUSTC) --crate-type lib foo.rs -Z dump-mono-stats=$(TMPDIR) -Zdump-mono-stats-format=json
+       cat $(TMPDIR)/foo.mono_items.json | $(CGREP) '"name":"bar"'
diff --git a/src/test/run-make/dump-mono-stats/foo.rs b/src/test/run-make/dump-mono-stats/foo.rs
new file mode 100644 (file)
index 0000000..c5c0bc6
--- /dev/null
@@ -0,0 +1 @@
+pub fn bar() {}
index fb8e288fae8825555755543529405da614372b55..c9b53a1a0f76c5b207c43377583f3bde26b310df 100644 (file)
@@ -3,70 +3,72 @@
 define-function: (
     "check-colors",
     (theme, main_color, title_color, fqn_color, fqn_type_color, src_link_color, sidebar_link_color),
-    [
-        ("goto", "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"),
+    block {
+        goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
         // This is needed to ensure that the text color is computed.
-        ("show-text", true),
+        show-text: true
 
         // Setting the theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
+        reload:
 
-        ("assert-css", ("#toggle-all-docs", {"color": |main_color|})),
-        ("assert-css", (".fqn a:nth-of-type(1)", {"color": |fqn_color|})),
-        ("assert-css", (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})),
-        ("assert-css", (
+        assert-css: ("#toggle-all-docs", {"color": |main_color|})
+        assert-css: (".fqn a:nth-of-type(1)", {"color": |fqn_color|})
+        assert-css: (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})
+        assert-css: (
              ".rightside .srclink",
              {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
              ALL,
-        )),
-        (
-            "compare-elements-css",
-            (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"]),
-        ),
-        (
-            "compare-elements-css",
-            (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"]),
-        ),
+        )
+        compare-elements-css: (
+            ".rightside .srclink",
+            ".rightside.srclink",
+            ["color", "text-decoration"],
+        )
+        compare-elements-css: (
+            ".main-heading .srclink",
+            ".rightside.srclink",
+            ["color", "text-decoration"],
+        )
 
-        ("move-cursor-to", ".main-heading .srclink"),
-        ("assert-css", (
+        move-cursor-to: ".main-heading .srclink"
+        assert-css: (
              ".main-heading .srclink",
              {"color": |src_link_color|, "text-decoration": "underline solid " + |src_link_color|},
-        )),
-        ("move-cursor-to", ".impl-items .rightside .srclink"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".impl-items .rightside .srclink"
+        assert-css: (
              ".impl-items .rightside .srclink",
              {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
-        )),
-        ("move-cursor-to", ".impl-items .rightside.srclink"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".impl-items .rightside.srclink"
+        assert-css: (
              ".impl-items .rightside.srclink",
              {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
-        )),
+        )
 
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"),
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
         // Since we changed page, we need to set the theme again.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
+        reload:
 
-        ("assert-css", ("#top-doc-prose-title", {"color": |title_color|})),
+        assert-css: ("#top-doc-prose-title", {"color": |title_color|})
 
-        ("assert-css", (".sidebar a", {"color": |sidebar_link_color|})),
-        ("assert-css", ("h1.fqn a", {"color": |title_color|})),
+        assert-css: (".sidebar a", {"color": |sidebar_link_color|})
+        assert-css: ("h1.fqn a", {"color": |title_color|})
 
         // We move the cursor over the "Implementations" title so the anchor is displayed.
-        ("move-cursor-to", "h2#implementations"),
-        ("assert-css", ("h2#implementations a.anchor", {"color": |main_color|})),
+        move-cursor-to: "h2#implementations"
+        assert-css: ("h2#implementations a.anchor", {"color": |main_color|})
 
         // Same thing with the impl block title.
-        ("move-cursor-to", "#impl-HeavilyDocumentedStruct"),
-        ("assert-css", ("#impl-HeavilyDocumentedStruct a.anchor", {"color": |main_color|})),
+        move-cursor-to: "#impl-HeavilyDocumentedStruct"
+        assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": |main_color|})
 
-        ("assert-css", ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})),
-    ],
+        assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
+    },
 )
 
 call-function: (
index 118f04ad6dcba9c32f2bceb6612b9aae8cd11950..cb550a4573a6f6c309fc66c45d807881324a29bc 100644 (file)
@@ -9,14 +9,14 @@ show-text: true
 define-function: (
     "check-colors",
     (theme, doc_code_color, doc_inline_code_color),
-    [
+    block {
         // Set the theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
-        ("assert-css", (".docblock pre > code", {"color": |doc_code_color|}, ALL)),
-        ("assert-css", (".docblock > p > code", {"color": |doc_inline_code_color|}, ALL)),
-    ],
+        reload:
+        assert-css: (".docblock pre > code", {"color": |doc_code_color|}, ALL)
+        assert-css: (".docblock > p > code", {"color": |doc_inline_code_color|}, ALL)
+    },
 )
 
 call-function: ("check-colors", ("ayu", "rgb(230, 225, 207)", "rgb(255, 180, 84)"))
index aab27394eb1f3b1b50d5ec902aa6a42ae61353eb..a3ef4e77b542421cfc302c1826d9d9f501cf618e 100644 (file)
@@ -5,131 +5,128 @@ show-text: true
 define-function: (
     "check-colors",
     (theme, background, color, border),
-    [
+    block {
         // Setting the theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
 
         // compile_fail block
-        ("assert-css", (
+        assert-css: (
             ".docblock .example-wrap.compile_fail .tooltip",
             {"color": "rgba(255, 0, 0, 0.5)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.compile_fail",
             {"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
-        )),
+        )
 
-        ("move-cursor-to", ".docblock .example-wrap.compile_fail .tooltip"),
+        move-cursor-to: ".docblock .example-wrap.compile_fail .tooltip"
 
-        ("assert-css", (
+        assert-css: (
             ".docblock .example-wrap.compile_fail .tooltip",
             {"color": "rgb(255, 0, 0)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.compile_fail",
             {"border-left": "2px solid rgb(255, 0, 0)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.compile_fail .tooltip::after",
             {
                 "content": '"This example deliberately fails to compile"',
-                "text-align": "center",
                 "padding": "5px 3px 3px",
                 "background-color": |background|,
                 "color": |color|,
                 "border": "1px solid " + |border|,
             },
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.compile_fail .tooltip::before",
             {
                 "border-width": "5px",
                 "border-style": "solid",
                 "border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
             },
-        )),
+        )
 
         // should_panic block
-        ("assert-css", (
+        assert-css: (
             ".docblock .example-wrap.should_panic .tooltip",
             {"color": "rgba(255, 0, 0, 0.5)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.should_panic",
             {"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
-        )),
+        )
 
-        ("move-cursor-to", ".docblock .example-wrap.should_panic .tooltip"),
+        move-cursor-to: ".docblock .example-wrap.should_panic .tooltip"
 
-        ("assert-css", (
+        assert-css: (
             ".docblock .example-wrap.should_panic .tooltip",
             {"color": "rgb(255, 0, 0)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.should_panic",
             {"border-left": "2px solid rgb(255, 0, 0)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.should_panic .tooltip::after",
             {
                 "content": '"This example panics"',
-                "text-align": "center",
                 "padding": "5px 3px 3px",
                 "background-color": |background|,
                 "color": |color|,
                 "border": "1px solid " + |border|,
             },
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.should_panic .tooltip::before",
             {
                 "border-width": "5px",
                 "border-style": "solid",
                 "border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
             },
-        )),
+        )
 
         // ignore block
-        ("assert-css", (
+        assert-css: (
             ".docblock .example-wrap.ignore .tooltip",
             {"color": "rgba(255, 142, 0, 0.6)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.ignore",
             {"border-left": "2px solid rgba(255, 142, 0, 0.6)"},
-        )),
+        )
 
-        ("move-cursor-to", ".docblock .example-wrap.ignore .tooltip"),
+        move-cursor-to: ".docblock .example-wrap.ignore .tooltip"
 
-        ("assert-css", (
+        assert-css: (
             ".docblock .example-wrap.ignore .tooltip",
             {"color": "rgb(255, 142, 0)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.ignore",
             {"border-left": "2px solid rgb(255, 142, 0)"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.ignore .tooltip::after",
             {
                 "content": '"This example is not tested"',
-                "text-align": "center",
                 "padding": "5px 3px 3px",
                 "background-color": |background|,
                 "color": |color|,
                 "border": "1px solid " + |border|,
             },
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".docblock .example-wrap.ignore .tooltip::before",
             {
                 "border-width": "5px",
                 "border-style": "solid",
                 "border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
             },
-        )),
-    ],
+        )
+    },
 )
 
 call-function: ("check-colors", {
index a3ed008719c00237a1cd50d51a74d8ed9ac8da6e..69bcf5339ef2cda8231dd7aebcbe12500dee78ae 100644 (file)
@@ -11,19 +11,19 @@ assert-false: "pre.example-line-numbers"
 define-function: (
     "check-colors",
     (theme, color),
-    [
+    block {
         // We now set the setting to show the line numbers on code examples.
-        ("local-storage", {
+        local-storage: {
             "rustdoc-theme": |theme|,
             "rustdoc-use-system-theme": "false",
             "rustdoc-line-numbers": "true"
-        }),
+        }
         // We reload to make the line numbers appear and change theme.
-        ("reload"),
+        reload:
         // We wait for them to be added into the DOM by the JS...
-        ("wait-for", "pre.example-line-numbers"),
+        wait-for: "pre.example-line-numbers"
         // If the test didn't fail, it means that it was found!
-        ("assert-css", (
+        assert-css: (
             "pre.example-line-numbers",
             {
                 "color": |color|,
@@ -32,8 +32,8 @@ define-function: (
                 "text-align": "right",
             },
             ALL,
-        )),
-    ],
+        )
+    },
 )
 call-function: ("check-colors", {
     "theme": "ayu",
index 8645c1b1949e3f79533a5d76345bea8aec5285b6..3dcb8abd41598887020e270a71a2ce012c59ecd5 100644 (file)
@@ -1,3 +1,4 @@
+// This test checks the appearance of the tables in the doc comments.
 goto: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func"
 
 compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"])
@@ -6,32 +7,32 @@ compare-elements-css: (".impl-items .docblock table td", ".top-doc .docblock tab
 define-function: (
     "check-colors",
     (theme, border_color, zebra_stripe_color),
-    [
-        ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
-        ("reload"),
-        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(1)", {
+    block {
+        local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
+        reload:
+        assert-css: (".top-doc .docblock table tbody tr:nth-child(1)", {
             "background-color": "rgba(0, 0, 0, 0)",
-        })),
-        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(2)", {
+        })
+        assert-css: (".top-doc .docblock table tbody tr:nth-child(2)", {
             "background-color": |zebra_stripe_color|,
-        })),
-        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(3)", {
+        })
+        assert-css: (".top-doc .docblock table tbody tr:nth-child(3)", {
             "background-color": "rgba(0, 0, 0, 0)",
-        })),
-        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(4)", {
+        })
+        assert-css: (".top-doc .docblock table tbody tr:nth-child(4)", {
             "background-color": |zebra_stripe_color|,
-        })),
-        ("assert-css", (".top-doc .docblock table td", {
+        })
+        assert-css: (".top-doc .docblock table td", {
             "border-style": "solid",
             "border-width": "1px",
             "border-color": |border_color|,
-        })),
-        ("assert-css", (".top-doc .docblock table th", {
+        })
+        assert-css: (".top-doc .docblock table th", {
             "border-style": "solid",
             "border-width": "1px",
             "border-color": |border_color|,
-        })),
-    ]
+        })
+    }
 )
 
 call-function: ("check-colors", {
index 78e9f23093ead1cfcec32f5203792cfa358d636e..5d80d24969ddeb638bd5684428f158e015a62a91 100644 (file)
@@ -5,7 +5,7 @@ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 write: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
-wait-for: "#search h1" // The search element is empty before the first search 
+wait-for: "#search h1" // The search element is empty before the first search
 // Check that the currently displayed element is search.
 wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
index c80a49c52f03a3e2af4c82b01c98064071f2acb9..92cf050a514ff24c9dd92bdb2f3abaac67da360c 100644 (file)
@@ -3,39 +3,39 @@
 define-function: (
     "check-colors",
     (theme, color, code_header_color, focus_background_color, headings_color),
-    [
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"),
+    block {
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
         // This is needed so that the text color is computed.
-        ("show-text", true),
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (
+        show-text: true
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (
             ".impl",
             {"color": |color|, "background-color": "rgba(0, 0, 0, 0)"},
             ALL,
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".impl .code-header",
             {"color": |code_header_color|, "background-color": "rgba(0, 0, 0, 0)"},
             ALL,
-        )),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"),
-        ("assert-css", (
+        )
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"
+        assert-css: (
             "#impl-Foo",
             {"color": |color|, "background-color": |focus_background_color|},
-        )),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"),
-        ("assert-css", (
+        )
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"
+        assert-css: (
             "#method\.must_use",
             {"color": |color|, "background-color": |focus_background_color|},
             ALL,
-        )),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
-        ("assert-css", (".small-section-header a", {"color": |color|}, ALL)),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"),
+        )
+        goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+        assert-css: (".small-section-header a", {"color": |color|}, ALL)
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
         // We select headings (h2, h3, h...).
-        ("assert-css", (".docblock > :not(p) > a", {"color": |headings_color|}, ALL)),
-    ],
+        assert-css: (".docblock > :not(p) > a", {"color": |headings_color|}, ALL)
+    },
 )
 
 call-function: (
index 85e17ca9551a2af896074ffc1f5a13dd4b4162e5..45b3fee26e413dc054a6ded9605a9f9b32434afd 100644 (file)
@@ -157,38 +157,38 @@ goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
 define-function: (
     "check-colors",
     (theme, heading_color, small_heading_color, heading_border_color),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (
             ".top-doc .docblock h2",
             {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".top-doc .docblock h3",
             {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".top-doc .docblock h4",
             {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".top-doc .docblock h5",
             {"color": |small_heading_color|, "border-bottom-width": "0px"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             "#implementations-list .docblock h4",
             {"color": |heading_color|, "border-bottom-width": "0px"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             "#implementations-list .docblock h5",
             {"color": |small_heading_color|, "border-bottom-width": "0px"},
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             "#implementations-list .docblock h6",
             {"color": |small_heading_color|, "border-bottom-width": "0px"},
-        )),
-    ],
+        )
+    },
 )
 call-function: (
     "check-colors",
@@ -221,11 +221,11 @@ call-function: (
 define-function: (
     "check-since-color",
     (theme),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|}),
-        ("reload"),
-        ("assert-css", (".since", {"color": "rgb(128, 128, 128)"}, ALL)),
-    ],
+    block {
+        local-storage: {"rustdoc-theme": |theme|}
+        reload:
+        assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
+    },
 )
 
 goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
index 80203901ed3c4c5c4678d48cd7a3461e4a3f1ca5..5f4c1ba2f8536d83f59281e0feaa92f3d5f454d5 100644 (file)
@@ -18,17 +18,17 @@ show-text: true
 define-function: (
     "check-colors",
     (theme, color, background, box_shadow),
-    [
+    block {
         // Setting the theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
-        ("assert-css", ("#help kbd", {
+        reload:
+        assert-css: ("#help kbd", {
             "color": |color|,
             "background-color": |background|,
             "box-shadow": |box_shadow| + " 0px -1px 0px 0px inset",
-        }, ALL)),
-    ],
+        }, ALL)
+    },
 )
 
 call-function: ("check-colors", {
@@ -39,7 +39,7 @@ call-function: ("check-colors", {
 })
 call-function: ("check-colors", {
     "theme": "dark",
-    "color": "rgb(221, 221, 221)",
+    "color": "rgb(0, 0, 0)",
     "background": "rgb(250, 251, 252)",
     "box_shadow": "rgb(198, 203, 209)",
 })
@@ -61,3 +61,12 @@ click: "#help-button > a"
 assert-css: ("#help", {"display": "none"})
 compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
 compare-elements-position-false: (".sub", "#help", ("x"))
+
+// This test ensures that the "the rustdoc book" anchor link within the help popover works.
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+size: (1000, 1000) // Popover only appears when the screen width is >700px.
+assert-false: "#help"
+click: "#help-button > a"
+click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']"
+wait-for: 2000
+assert-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"}
index ff1be389dcb07af1a3d34047ff4cf6ee74af63f0..b182150a577d56616b2d11414c39af4a744e33ad 100644 (file)
@@ -21,24 +21,24 @@ define-function: (
         comment,
         doc_comment,
     ),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", ("pre.rust .kw", {"color": |kw|}, ALL)),
-        ("assert-css", ("pre.rust .kw-2", {"color": |kw2|}, ALL)),
-        ("assert-css", ("pre.rust .prelude-ty", {"color": |prelude_ty|}, ALL)),
-        ("assert-css", ("pre.rust .prelude-val", {"color": |prelude_val|}, ALL)),
-        ("assert-css", ("pre.rust .lifetime", {"color": |lifetime|}, ALL)),
-        ("assert-css", ("pre.rust .number", {"color": |number|}, ALL)),
-        ("assert-css", ("pre.rust .string", {"color": |string|}, ALL)),
-        ("assert-css", ("pre.rust .bool-val", {"color": |bool_val|}, ALL)),
-        ("assert-css", ("pre.rust .self", {"color": |self|}, ALL)),
-        ("assert-css", ("pre.rust .attr", {"color": |attr|}, ALL)),
-        ("assert-css", ("pre.rust .macro", {"color": |macro|}, ALL)),
-        ("assert-css", ("pre.rust .question-mark", {"color": |question_mark|}, ALL)),
-        ("assert-css", ("pre.rust .comment", {"color": |comment|}, ALL)),
-        ("assert-css", ("pre.rust .doccomment", {"color": |doc_comment|}, ALL)),
-    ],
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: ("pre.rust .kw", {"color": |kw|}, ALL)
+        assert-css: ("pre.rust .kw-2", {"color": |kw2|}, ALL)
+        assert-css: ("pre.rust .prelude-ty", {"color": |prelude_ty|}, ALL)
+        assert-css: ("pre.rust .prelude-val", {"color": |prelude_val|}, ALL)
+        assert-css: ("pre.rust .lifetime", {"color": |lifetime|}, ALL)
+        assert-css: ("pre.rust .number", {"color": |number|}, ALL)
+        assert-css: ("pre.rust .string", {"color": |string|}, ALL)
+        assert-css: ("pre.rust .bool-val", {"color": |bool_val|}, ALL)
+        assert-css: ("pre.rust .self", {"color": |self|}, ALL)
+        assert-css: ("pre.rust .attr", {"color": |attr|}, ALL)
+        assert-css: ("pre.rust .macro", {"color": |macro|}, ALL)
+        assert-css: ("pre.rust .question-mark", {"color": |question_mark|}, ALL)
+        assert-css: ("pre.rust .comment", {"color": |comment|}, ALL)
+        assert-css: ("pre.rust .doccomment", {"color": |doc_comment|}, ALL)
+    },
 )
 
 call-function: ("check-colors", {
index 7322032b3f5f7d6f6003154308520db422380619..6caffb9c39fc1b4210034753ad8e3251f7bad4db 100644 (file)
@@ -3,7 +3,7 @@ goto: "file://" + |DOC_PATH| + "/test_docs/struct.TypeWithImplDoc.html"
 
 // The text is about 24px tall, so if there's a margin, then their position will be >24px apart
 compare-elements-position-near-false: (
-       "#implementations-list > .implementors-toggle > .docblock > p",
-       "#implementations-list > .implementors-toggle > .impl-items",
-       {"y": 24}
+    "#implementations-list > .implementors-toggle > .docblock > p",
+    "#implementations-list > .implementors-toggle > .impl-items",
+    {"y": 24}
 )
index 4999283dc8b911cd1f18c76d3cb980fa765a84d1..997c0ed8f017ca7fdf8c913f7a0b58fbbd6f5435 100644 (file)
@@ -33,3 +33,9 @@ goto: "file://" + |DOC_PATH| + "/lib2/trait.TraitToReexport.html"
 assert-count: ("#implementors-list .impl", 1)
 goto: "file://" + |DOC_PATH| + "/implementors/trait.TraitToReexport.html"
 assert-count: ("#implementors-list .impl", 1)
+
+// Now check that the link is properly rewritten for a crate called `http`.
+// An older version of rustdoc had a buggy check for absolute links.
+goto: "file://" + |DOC_PATH| + "/http/trait.HttpTrait.html"
+assert-count: ("#implementors-list .impl", 1)
+assert-attribute: ("#implementors-list .impl a.trait", {"href": "../http/trait.HttpTrait.html"})
index 2e07f19b13d649fb4fdb0b62f016dd44d146e8e1..c58e3eb7c237f5ea5dcb5e5e392034eb33171330 100644 (file)
@@ -17,22 +17,23 @@ define-function: (
         fn_color,
         assoc_type_color,
     ),
-    [
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"),
-        ("show-text", true),
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (".item-decl .code-attribute", {"color": |attr_color|}, ALL)),
-        ("assert-css", (".item-decl .trait", {"color": |trait_color|}, ALL)),
+    block {
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"
+        show-text: true
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (".item-decl .code-attribute", {"color": |attr_color|}, ALL)
+        assert-css: (".item-decl .trait", {"color": |trait_color|}, ALL)
         // We need to add `code` here because otherwise it would select the parent too.
-        ("assert-css", (".item-decl code .struct", {"color": |struct_color|}, ALL)),
-        ("assert-css", (".item-decl .enum", {"color": |enum_color|}, ALL)),
-        ("assert-css", (".item-decl .primitive", {"color": |primitive_color|}, ALL)),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html"),
-        ("assert-css", (".item-decl .constant", {"color": |constant_color|}, ALL)),
-        ("assert-css", (".item-decl .fn", {"color": |fn_color|}, ALL)),
-        ("assert-css", (".item-decl .associatedtype", {"color": |assoc_type_color|}, ALL)),
-    ],
+        assert-css: (".item-decl code .struct", {"color": |struct_color|}, ALL)
+        assert-css: (".item-decl .enum", {"color": |enum_color|}, ALL)
+        assert-css: (".item-decl .primitive", {"color": |primitive_color|}, ALL)
+
+        goto: "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html"
+        assert-css: (".item-decl .constant", {"color": |constant_color|}, ALL)
+        assert-css: (".item-decl .fn", {"color": |fn_color|}, ALL)
+        assert-css: (".item-decl .associatedtype", {"color": |assoc_type_color|}, ALL)
+    },
 )
 
 call-function: (
index b65faf13d0c5335b4881fe06a754fc536f1fe2ce..8ee3ccf4a211897251aceeee96807847dc257bb3 100644 (file)
@@ -4,17 +4,17 @@ goto: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html"
 define-function: (
     "check-background-color",
     (theme, background_color),
-    [
+    block {
         // Set the theme.
-        ("local-storage", { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }),
+        local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
         // We reload the page so the local storage settings are being used.
-        ("reload"),
-        ("assert-css", (
+        reload:
+        assert-css: (
             "body.source .example-wrap pre.rust a",
             {"background-color": |background_color|},
             ALL,
-        )),
-    ],
+        )
+    },
 )
 
 call-function: ("check-background-color", ("ayu", "rgb(51, 51, 51)"))
index 9402c09eb69e719c27b1fa93800b3a89e3851d10..14f7d99351a646364d9ba5cdf9e58324fc6cd940 100644 (file)
@@ -8,29 +8,29 @@ define-function: (
     "check-colors",
     (theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
      sidebar, sidebar_current, sidebar_current_background),
-    [
-        ("local-storage", {
+    block {
+        local-storage: {
             "rustdoc-theme": |theme|,
             "rustdoc-use-system-theme": "false",
-        }),
-        ("reload"),
+        }
+        reload:
         // Checking results colors.
-        ("assert-css", (".item-table .mod", {"color": |mod|}, ALL)),
-        ("assert-css", (".item-table .macro", {"color": |macro|}, ALL)),
-        ("assert-css", (".item-table .struct", {"color": |struct|}, ALL)),
-        ("assert-css", (".item-table .enum", {"color": |enum|}, ALL)),
-        ("assert-css", (".item-table .trait", {"color": |trait|}, ALL)),
-        ("assert-css", (".item-table .fn", {"color": |fn|}, ALL)),
-        ("assert-css", (".item-table .type", {"color": |type|}, ALL)),
-        ("assert-css", (".item-table .union", {"color": |union|}, ALL)),
-        ("assert-css", (".item-table .keyword", {"color": |keyword|}, ALL)),
+        assert-css: (".item-table .mod", {"color": |mod|}, ALL)
+        assert-css: (".item-table .macro", {"color": |macro|}, ALL)
+        assert-css: (".item-table .struct", {"color": |struct|}, ALL)
+        assert-css: (".item-table .enum", {"color": |enum|}, ALL)
+        assert-css: (".item-table .trait", {"color": |trait|}, ALL)
+        assert-css: (".item-table .fn", {"color": |fn|}, ALL)
+        assert-css: (".item-table .type", {"color": |type|}, ALL)
+        assert-css: (".item-table .union", {"color": |union|}, ALL)
+        assert-css: (".item-table .keyword", {"color": |keyword|}, ALL)
         // Checking sidebar elements.
-        ("assert-css", (
+        assert-css: (
             ".sidebar-elems a:not(.current)",
             {"color": |sidebar|, "background-color": "rgba(0, 0, 0, 0)", "font-weight": "400"},
             ALL,
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".sidebar-elems a.current",
             {
                 "color": |sidebar_current|,
@@ -38,8 +38,8 @@ define-function: (
                 "font-weight": "500",
             },
             ALL,
-        )),
-    ],
+        )
+    },
 )
 
 call-function: (
index 704542a39d21b5678c50f3227306c0ab4842cda0..895864d89445fdfe85f57d799e276818d0517f5f 100644 (file)
@@ -27,4 +27,8 @@ assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since
 goto: "file://" + |DOC_PATH| + "/settings.html"
 size: (400, 600)
 // Ignored for now https://github.com/rust-lang/rust/issues/93784.
-// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
+// compare-elements-position-near-false: (
+//     "#preferred-light-theme .setting-name",
+//     "#preferred-light-theme .choice",
+//     {"y": 16},
+// )
index 7d4bd27d42d4d20feacb7823d98142c007c8aff3..b4fa7d0dbf0e2a69ec820ba0675d6af5f9106dd6 100644 (file)
@@ -123,40 +123,40 @@ assert-count: ("//*[@class='notable popover']", 0)
 define-function: (
     "check-colors",
     (theme, header_color, content_color, type_color, trait_color),
-    [
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"),
+    block {
+        goto: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
         // This is needed to ensure that the text color is computed.
-        ("show-text", true),
+        show-text: true
 
         // Setting the theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
+        reload:
 
-        ("move-cursor-to", "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"),
-        ("assert-count", (".notable.popover", 1)),
+        move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+        assert-count: (".notable.popover", 1)
 
-        ("assert-css", (
+        assert-css: (
              ".notable.popover h3",
              {"color": |header_color|},
              ALL,
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
              ".notable.popover pre",
              {"color": |content_color|},
              ALL,
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
              ".notable.popover pre a.struct",
              {"color": |type_color|},
              ALL,
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
              ".notable.popover pre a.trait",
              {"color": |trait_color|},
              ALL,
-        )),
-    ]
+        )
+    },
 )
 
 call-function: (
index 57d63049f28ca1429f3335e0658f09e1b757fd8d..8dcb62c10aaac9a4ab80f0f3efffab03a59d2cc3 100644 (file)
@@ -8,27 +8,27 @@ show-text: true
 define-function: (
     "check-run-button",
     (theme, color, background, hover_color, hover_background),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (".test-arrow", {"visibility": "hidden"})),
-        ("move-cursor-to", ".example-wrap"),
-        ("assert-css", (".test-arrow", {
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (".test-arrow", {"visibility": "hidden"})
+        move-cursor-to: ".example-wrap"
+        assert-css: (".test-arrow", {
             "visibility": "visible",
             "color": |color|,
             "background-color": |background|,
             "font-size": "22px",
             "border-radius": "5px",
-        })),
-        ("move-cursor-to", ".test-arrow"),
-        ("assert-css", (".test-arrow:hover", {
+        })
+        move-cursor-to: ".test-arrow"
+        assert-css: (".test-arrow:hover", {
             "visibility": "visible",
             "color": |hover_color|,
             "background-color": |hover_background|,
             "font-size": "22px",
             "border-radius": "5px",
-        })),
-    ],
+        })
+    },
 )
 
 call-function: ("check-run-button", {
index 816cc9abd693dca67daeeed89d728804e9db67c5..2d15e8b969921d4b1ea801bea88af2dba61e1ea0 100644 (file)
@@ -4,40 +4,55 @@ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 define-function: (
     "check-logo",
     (theme, filter),
-    [
+    block {
         // Going to the doc page.
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
+        goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
         // Changing theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (".rust-logo", {"filter": |filter|})),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (".rust-logo", {"filter": |filter|})
         // Going to the source code page.
-        ("goto", "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"),
+        goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
         // Changing theme (since it's local files, the local storage works by folder).
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (".rust-logo", {"filter": |filter|})),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (".rust-logo", {"filter": |filter|})
         // Now we check that the non-rust logos don't have a CSS filter set.
-        ("goto", "file://" + |DOC_PATH| + "/huge_logo/index.html"),
+        goto: "file://" + |DOC_PATH| + "/huge_logo/index.html"
         // Changing theme on the new page (again...).
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
         // Check there is no rust logo
-        ("assert-false", ".rust-logo"),
+        assert-false: ".rust-logo"
         // Check there is no filter.
-        ("assert-css", (".sidebar .logo-container img", {"filter": "none"})),
-    ],
+        assert-css: (".sidebar .logo-container img", {"filter": "none"})
+    },
 )
 
 call-function: (
     "check-logo",
-    ("ayu", "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"),
+    {
+        "theme": "ayu",
+        "filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) " +
+            "drop-shadow(rgb(255, 255, 255) 0px 1px 0px) " +
+            "drop-shadow(rgb(255, 255, 255) -1px 0px 0px) " +
+            "drop-shadow(rgb(255, 255, 255) 0px -1px 0px)",
+    },
 )
 call-function: (
     "check-logo",
-    ("dark", "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"),
+    {
+        "theme": "dark",
+        "filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) " +
+            "drop-shadow(rgb(255, 255, 255) 0px 1px 0px) " +
+            "drop-shadow(rgb(255, 255, 255) -1px 0px 0px) " +
+            "drop-shadow(rgb(255, 255, 255) 0px -1px 0px)",
+    },
 )
 call-function: (
     "check-logo",
-    ("light", "none"),
+    {
+        "theme": "light",
+        "filter": "none",
+    },
 )
index bba518db099a49693956915158ffb3e224478716..10651a3f6696d5ef41eaef999ee37c527446b97a 100644 (file)
@@ -5,25 +5,25 @@ store-property: (initialScrollTop, ".scraped-example-list > .scraped-example pre
 focus: ".scraped-example-list > .scraped-example .next"
 press-key: "Enter"
 assert-property-false: (".scraped-example-list > .scraped-example pre", {
-       "scrollTop": |initialScrollTop|
+    "scrollTop": |initialScrollTop|
 })
 focus: ".scraped-example-list > .scraped-example .prev"
 press-key: "Enter"
 assert-property: (".scraped-example-list > .scraped-example pre", {
-       "scrollTop": |initialScrollTop|
+    "scrollTop": |initialScrollTop|
 })
 
 // The expand button increases the scrollHeight of the minimized code viewport
 store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
 assert-property-false: (".scraped-example-list > .scraped-example pre", {
-       "scrollHeight": |smallOffsetHeight|
+    "scrollHeight": |smallOffsetHeight|
 })
 focus: ".scraped-example-list > .scraped-example .expand"
 press-key: "Enter"
 assert-property-false: (".scraped-example-list > .scraped-example pre", {
-       "offsetHeight": |smallOffsetHeight|
+    "offsetHeight": |smallOffsetHeight|
 })
 store-property: (fullOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
 assert-property: (".scraped-example-list > .scraped-example pre", {
-       "scrollHeight": |fullOffsetHeight|
+    "scrollHeight": |fullOffsetHeight|
 })
diff --git a/src/test/rustdoc-gui/scrape-examples-color.goml b/src/test/rustdoc-gui/scrape-examples-color.goml
new file mode 100644 (file)
index 0000000..40f31b2
--- /dev/null
@@ -0,0 +1,60 @@
+// Check that scrape example code blocks have the expected colors.
+goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
+show-text: true
+
+define-function: (
+    "check-colors",
+    (theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
+     help_hover_color),
+    block {
+        local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
+        reload:
+        wait-for: ".more-examples-toggle"
+        assert-css: (".scraped-example .example-wrap .rust span.highlight:not(.focus)", {
+            "background-color": |highlight|,
+        }, ALL)
+        assert-css: (".scraped-example .example-wrap .rust span.highlight.focus", {
+            "background-color": |highlight_focus|,
+        }, ALL)
+
+        assert-css: (".scraped-example-list .scrape-help", {
+            "border-color": |help_border|,
+            "color": |help_color|,
+        })
+        move-cursor-to: ".scraped-example-list .scrape-help"
+        assert-css: (".scraped-example-list .scrape-help:hover", {
+            "border-color": |help_hover_border|,
+            "color": |help_hover_color|,
+        })
+        // Moving the cursor to another item to not break next runs.
+        move-cursor-to: ".search-input"
+    }
+)
+
+call-function: ("check-colors", {
+    "theme": "ayu",
+    "highlight": "rgb(91, 59, 1)",
+    "highlight_focus": "rgb(124, 75, 15)",
+    "help_border": "rgb(170, 170, 170)",
+    "help_color": "rgb(238, 238, 238)",
+    "help_hover_border": "rgb(255, 255, 255)",
+    "help_hover_color": "rgb(255, 255, 255)",
+})
+call-function: ("check-colors", {
+    "theme": "dark",
+    "highlight": "rgb(91, 59, 1)",
+    "highlight_focus": "rgb(124, 75, 15)",
+    "help_border": "rgb(170, 170, 170)",
+    "help_color": "rgb(238, 238, 238)",
+    "help_hover_border": "rgb(255, 255, 255)",
+    "help_hover_color": "rgb(255, 255, 255)",
+})
+call-function: ("check-colors", {
+    "theme": "light",
+    "highlight": "rgb(252, 255, 214)",
+    "highlight_focus": "rgb(246, 253, 176)",
+    "help_border": "rgb(85, 85, 85)",
+    "help_color": "rgb(51, 51, 51)",
+    "help_hover_border": "rgb(0, 0, 0)",
+    "help_hover_color": "rgb(0, 0, 0)",
+})
index b7d7f4ccb4ae6b0e67f687cc0a2dfeba8c14a715..142f337cb74e4d5780367a1801af87d50a9548cd 100644 (file)
@@ -1,3 +1,4 @@
+// This test ensures that the correct font is used in scraped examples.
 goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
 
 store-value: (font, '"Fira Sans", Arial, NanumBarunGothic, sans-serif')
index fde9a0ab0bc3095f09164a131de10da405c82983..95102528ec11d7343f8c18c61c0bb4ade224fe0d 100644 (file)
@@ -33,3 +33,17 @@ assert-property: (
     ".more-scraped-examples .scraped-example:nth-child(6) .code-wrapper .src-line-numbers",
     {"clientWidth": |clientWidth|}
 )
+
+// Check that for both mobile and desktop sizes, the buttons in scraped examples are displayed
+// correctly.
+
+store-value: (offset_y, 4)
+
+// First with desktop
+assert-position: (".scraped-example .code-wrapper", {"y": 255})
+assert-position: (".scraped-example .code-wrapper .prev", {"y": 255 + |offset_y|})
+
+// Then with mobile
+size: (600, 600)
+assert-position: (".scraped-example .code-wrapper", {"y": 314})
+assert-position: (".scraped-example .code-wrapper .prev", {"y": 314 + |offset_y|})
index 8c84fbc0c30568d121d08aa2a289697d7b10c451..2d5df6a5d25e0d7efdaff29f7d7f2704e1f2f222 100644 (file)
@@ -6,24 +6,24 @@ show-text: true
 define-function: (
     "check-color",
     (theme, toggle_line_color, toggle_line_hover_color),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
 
         // Clicking "More examples..." will open additional examples
-        ("assert-attribute-false", (".more-examples-toggle", {"open": ""})),
-        ("click", ".more-examples-toggle"),
-        ("assert-attribute", (".more-examples-toggle", {"open": ""})),
+        assert-attribute-false: (".more-examples-toggle", {"open": ""})
+        click: ".more-examples-toggle"
+        assert-attribute: (".more-examples-toggle", {"open": ""})
 
-        ("assert-css", (".toggle-line-inner", {"background-color": |toggle_line_color|}, ALL)),
-        ("move-cursor-to", ".toggle-line"),
-        ("assert-css", (
+        assert-css: (".toggle-line-inner", {"background-color": |toggle_line_color|}, ALL)
+        move-cursor-to: ".toggle-line"
+        assert-css: (
             ".toggle-line:hover .toggle-line-inner",
             {"background-color": |toggle_line_hover_color|},
-        )),
+        )
         // Moving cursor away from the toggle line to prevent disrupting next test.
-        ("move-cursor-to", ".search-input"),
-    ],
+        move-cursor-to: ".search-input"
+    },
 )
 
 call-function: ("check-color", {
index e556da0c54ebafc55ac6da342a7d4d0bd3666afa..5bc6e87d6d24da23ef2943ada0e69c75d0645180 100644 (file)
@@ -15,6 +15,7 @@ click: "#crate-search"
 press-key: "ArrowDown"
 press-key: "ArrowDown"
 press-key: "ArrowDown"
+press-key: "ArrowDown"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
@@ -39,6 +40,7 @@ click: "#crate-search"
 press-key: "ArrowUp"
 press-key: "ArrowUp"
 press-key: "ArrowUp"
+press-key: "ArrowUp"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
index b88be32c94a4bb01212a7ab1ca10915fde18a6a9..b76a44fa992e636a1532c9d550bab4419b2ffb79 100644 (file)
@@ -5,18 +5,18 @@ show-text: true
 define-function: (
     "check-no-result",
     (theme, link, link_hover),
-    [
+    block {
         // Changing theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("wait-for", "#results"),
-        ("assert", ".search-failed.active"),
-        ("assert-css", ("#results a", {"color": |link|}, ALL)),
-        ("move-cursor-to", "#results a"),
-        ("assert-css", ("#results a:hover", {"color": |link_hover|})),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        wait-for: "#results"
+        assert: ".search-failed.active"
+        assert-css: ("#results a", {"color": |link|}, ALL)
+        move-cursor-to: "#results a"
+        assert-css: ("#results a:hover", {"color": |link_hover|})
         // Moving the cursor to some other place to not create issues with next function run.
-        ("move-cursor-to", ".search-input"),
-    ]
+        move-cursor-to: ".search-input"
+    },
 )
 
 call-function: ("check-no-result", {
index 3c5fe9b74b74facba0b7685db5cc2e3dac87894e..d6d54ec4bee9bee2aa5be69ddb3a6d286511285d 100644 (file)
@@ -3,53 +3,32 @@
 define-function: (
     "check-result-color",
     (result_kind, color, hover_color),
-    [
-        (
-            "assert-css",
-            (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL),
-        ),
-        (
-            "assert-css",
-            (
-                ".result-" + |result_kind|,
-                {"color": |entry_color|, "background-color": |background_color|},
-            ),
-        ),
-        (
-            "move-cursor-to",
+    block {
+        assert-css: (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL)
+        assert-css: (
             ".result-" + |result_kind|,
-        ),
-        (
-            "assert-css",
-            (
-                ".result-" + |result_kind| + ":hover",
-                {"color": |hover_entry_color|, "background-color": |hover_background_color|},
-            ),
-        ),
-        (
-            "assert-css",
-            (".result-" + |result_kind| + ":hover ." + |result_kind|, {"color": |hover_color|}),
-        ),
-        (
-            "move-cursor-to",
-            ".search-input",
-        ),
-        (
-            "focus",
-            ".result-" + |result_kind|,
-        ),
-        (
-            "assert-css",
-            (
-                ".result-" + |result_kind| + ":focus",
-                {"color": |hover_entry_color|, "background-color": |hover_background_color|},
-            ),
-        ),
-        (
-            "assert-css",
-            (".result-" + |result_kind| + ":focus ." + |result_kind|, {"color": |hover_color|}),
-        ),
-    ],
+            {"color": |entry_color|, "background-color": |background_color|},
+        )
+        move-cursor-to: ".result-" + |result_kind|
+        assert-css: (
+            ".result-" + |result_kind| + ":hover",
+            {"color": |hover_entry_color|, "background-color": |hover_background_color|},
+        )
+        assert-css: (
+            ".result-" + |result_kind| + ":hover ." + |result_kind|,
+            {"color": |hover_color|},
+        )
+        move-cursor-to: ".search-input"
+        focus: ".result-" + |result_kind|
+        assert-css: (
+            ".result-" + |result_kind| + ":focus",
+            {"color": |hover_entry_color|, "background-color": |hover_background_color|},
+        )
+        assert-css: (
+            ".result-" + |result_kind| + ":focus ." + |result_kind|,
+            {"color": |hover_color|},
+        )
+    },
 )
 
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo"
@@ -389,20 +368,20 @@ show-text: true
 define-function: (
     "check-alias",
     (theme, alias, grey),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("write", (".search-input", "thisisanalias")),
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        write: (".search-input", "thisisanalias")
         // To be SURE that the search will be run.
-        ("press-key", 'Enter'),
+        press-key: 'Enter'
         // Waiting for the search results to appear...
-        ("wait-for", "#search-tabs"),
+        wait-for: "#search-tabs"
         // Checking that the colors for the alias element are the ones expected.
-        ("assert-css", (".result-name > .alias", {"color": |alias|})),
-        ("assert-css", (".result-name > .alias > .grey", {"color": |grey|})),
+        assert-css: (".result-name > .alias", {"color": |alias|})
+        assert-css: (".result-name > .alias > .grey", {"color": |grey|})
         // Leave the search results to prevent reloading with an already filled search input.
-        ("press-key", "Escape"),
-    ],
+        press-key: "Escape"
+    },
 )
 
 call-function: ("check-alias", {
index 13a5e4c717b65ca35bca87a7e4b699c9ac103308..43e608228d8e32d3159b0108d27b8e44f8b2be92 100644 (file)
@@ -42,17 +42,17 @@ show-text: true
 define-function: (
     "check-filter",
     (theme, border, filter, hover_border, hover_filter),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("wait-for", "#crate-search"),
-        ("assert-css", ("#crate-search", {"border": "1px solid " + |border|})),
-        ("assert-css", ("#crate-search-div::after", {"filter": |filter|})),
-        ("move-cursor-to", "#crate-search"),
-        ("assert-css", ("#crate-search", {"border": "1px solid " + |hover_border|})),
-        ("assert-css", ("#crate-search-div::after", {"filter": |hover_filter|})),
-        ("move-cursor-to", ".search-input"),
-    ],
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        wait-for: "#crate-search"
+        assert-css: ("#crate-search", {"border": "1px solid " + |border|})
+        assert-css: ("#crate-search-div::after", {"filter": |filter|})
+        move-cursor-to: "#crate-search"
+        assert-css: ("#crate-search", {"border": "1px solid " + |hover_border|})
+        assert-css: ("#crate-search-div::after", {"filter": |hover_filter|})
+        move-cursor-to: ".search-input"
+    },
 )
 
 call-function: ("check-filter", {
diff --git a/src/test/rustdoc-gui/search-tab.goml b/src/test/rustdoc-gui/search-tab.goml
new file mode 100644 (file)
index 0000000..36958f7
--- /dev/null
@@ -0,0 +1,76 @@
+// Checking the colors of the search tab headers.
+goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html?search=something"
+show-text: true
+
+define-function: (
+    "check-colors",
+    (theme, background, background_selected, background_hover, border_bottom,
+     border_bottom_selected, border_bottom_hover, border_top, border_top_selected,
+     border_top_hover),
+    block {
+        // Setting the theme.
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+
+        // These two commands are used to be sure the search will be run.
+        focus: ".search-input"
+        press-key: "Enter"
+
+        wait-for: "#search-tabs"
+        assert-css: ("#search-tabs > button:not(.selected)", {
+            "background-color": |background|,
+            "border-bottom": |border_bottom|,
+            "border-top": |border_top|,
+        })
+        assert-css: ("#search-tabs > button.selected", {
+            "background-color": |background_selected|,
+            "border-bottom": |border_bottom_selected|,
+            "border-top": |border_top_selected|,
+        })
+        move-cursor-to: "#search-tabs > button:not(.selected)"
+        assert-css: ("#search-tabs > button:not(.selected):hover", {
+            "background-color": |background_hover|,
+            "border-bottom": |border_bottom_hover|,
+            "border-top": |border_top_hover|,
+        })
+        // To prevent disrupting next run of this function.
+        move-cursor-to: ".search-input"
+    },
+)
+
+call-function: ("check-colors", {
+    "theme": "ayu",
+    "background": "rgba(0, 0, 0, 0)",
+    "background_selected": "rgb(20, 25, 32)",
+    "background_hover": "rgba(0, 0, 0, 0)",
+    "border_bottom": "0px none rgb(197, 197, 197)",
+    "border_bottom_selected": "1px solid rgb(255, 180, 76)",
+    "border_bottom_hover": "1px solid rgba(242, 151, 24, 0.3)",
+    "border_top": "0px none rgb(197, 197, 197)",
+    "border_top_selected": "0px none rgb(197, 197, 197)",
+    "border_top_hover": "0px none rgb(197, 197, 197)",
+})
+call-function: ("check-colors", {
+    "theme": "dark",
+    "background": "rgb(37, 37, 37)",
+    "background_selected": "rgb(53, 53, 53)",
+    "background_hover": "rgb(53, 53, 53)",
+    "border_bottom": "0px none rgb(221, 221, 221)",
+    "border_bottom_selected": "0px none rgb(221, 221, 221)",
+    "border_bottom_hover": "0px none rgb(221, 221, 221)",
+    "border_top": "2px solid rgb(37, 37, 37)",
+    "border_top_selected": "2px solid rgb(0, 137, 255)",
+    "border_top_hover": "2px solid rgb(0, 137, 255)",
+})
+call-function: ("check-colors", {
+    "theme": "light",
+    "background": "rgb(230, 230, 230)",
+    "background_selected": "rgb(255, 255, 255)",
+    "background_hover": "rgb(255, 255, 255)",
+    "border_bottom": "0px none rgb(0, 0, 0)",
+    "border_bottom_selected": "0px none rgb(0, 0, 0)",
+    "border_bottom_hover": "0px none rgb(0, 0, 0)",
+    "border_top": "2px solid rgb(230, 230, 230)",
+    "border_top_selected": "2px solid rgb(0, 137, 255)",
+    "border_top_hover": "2px solid rgb(0, 137, 255)",
+})
index 7ef7ec90cd26910fb3a591bb7708f311c01c31a4..1d5fdb7a48fc71e42c04b99a2daf1381c2fdec21 100644 (file)
@@ -12,80 +12,80 @@ define-function: (
         trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
         type_hover_background, keyword, keyword_hover, keyword_hover_background,
     ),
-    [
-        ("local-storage", { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }),
-        ("reload"),
+    block {
+        local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
+        reload:
         // Struct
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.struct a:not(.current)",
             {"color": |struct|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.struct a:not(.current)"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.struct a:not(.current)"
+        assert-css: (
             ".sidebar .block.struct a:hover",
             {"color": |struct_hover|, "background-color": |struct_hover_background|},
-        )),
+        )
         // Enum
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.enum a",
             {"color": |enum|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.enum a"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.enum a"
+        assert-css: (
             ".sidebar .block.enum a:hover",
             {"color": |enum_hover|, "background-color": |enum_hover_background|},
-        )),
+        )
         // Union
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.union a",
             {"color": |union|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.union a"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.union a"
+        assert-css: (
             ".sidebar .block.union a:hover",
             {"color": |union_hover|, "background-color": |union_hover_background|},
-        )),
+        )
         // Trait
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.trait a",
             {"color": |trait|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.trait a"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.trait a"
+        assert-css: (
             ".sidebar .block.trait a:hover",
             {"color": |trait_hover|, "background-color": |trait_hover_background|},
-        )),
+        )
         // Function
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.fn a",
             {"color": |fn|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.fn a"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.fn a"
+        assert-css: (
             ".sidebar .block.fn a:hover",
             {"color": |fn_hover|, "background-color": |fn_hover_background|},
-        )),
+        )
         // Type definition
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.type a",
             {"color": |type|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.type a"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.type a"
+        assert-css: (
             ".sidebar .block.type a:hover",
             {"color": |type_hover|, "background-color": |type_hover_background|},
-        )),
+        )
         // Keyword
-        ("assert-css", (
+        assert-css: (
             ".sidebar .block.keyword a",
             {"color": |keyword|, "background-color": "rgba(0, 0, 0, 0)"},
-        )),
-        ("move-cursor-to", ".sidebar .block.keyword a"),
-        ("assert-css", (
+        )
+        move-cursor-to: ".sidebar .block.keyword a"
+        assert-css: (
             ".sidebar .block.keyword a:hover",
             {"color": |keyword_hover|, "background-color": |keyword_hover_background|},
-        )),
-    ]
+        )
+    }
 )
 
 call-function: (
index 38d01f7f612a5a0cbd99dcf05d24c4a8aeff3e83..d5f4b619629e3caada7fb31ee5f032b70f1e3e8c 100644 (file)
@@ -58,17 +58,17 @@ show-text: true
 define-function: (
     "check-colors",
     (theme, color, background),
-    [
-        ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
-        ("reload"),
+    block {
+        local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
+        reload:
 
         // Open the sidebar menu.
-        ("click", ".sidebar-menu-toggle"),
-        ("assert-css", (".sidebar", {
+        click: ".sidebar-menu-toggle"
+        assert-css: (".sidebar", {
             "background-color": |background|,
             "color": |color|,
-        })),
-    ],
+        })
+    },
 )
 
 call-function: ("check-colors", {
index df4506e1119648a7c76f379170da131cab39d51f..f3eb8ff76a38b945f0950d5f2d79bf3a339ca116 100644 (file)
@@ -35,88 +35,88 @@ define-function: (
         theme, color, color_hover, background, background_hover, background_toggle,
         background_toggle_hover,
     ),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("wait-for-css", ("#src-sidebar-toggle", {"visibility": "visible"})),
-        ("assert-css", (
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        wait-for-css: ("#src-sidebar-toggle", {"visibility": "visible"})
+        assert-css: (
             "#source-sidebar details[open] > .files a.selected",
             {"color": |color_hover|, "background-color": |background|},
-        )),
+        )
 
         // Without hover or focus.
-        ("assert-css", ("#src-sidebar-toggle > button", {"background-color": |background_toggle|})),
+        assert-css: ("#src-sidebar-toggle > button", {"background-color": |background_toggle|})
         // With focus.
-        ("focus", "#src-sidebar-toggle > button"),
-        ("assert-css", (
+        focus: "#src-sidebar-toggle > button"
+        assert-css: (
             "#src-sidebar-toggle > button:focus",
             {"background-color": |background_toggle_hover|},
-        )),
-        ("focus", ".search-input"),
+        )
+        focus: ".search-input"
         // With hover.
-        ("move-cursor-to", "#src-sidebar-toggle > button"),
-        ("assert-css", (
+        move-cursor-to: "#src-sidebar-toggle > button"
+        assert-css: (
             "#src-sidebar-toggle > button:hover",
             {"background-color": |background_toggle_hover|},
-        )),
+        )
 
         // Without hover or focus.
-        ("assert-css", (
+        assert-css: (
             "#source-sidebar details[open] > .files a:not(.selected)",
             {"color": |color|, "background-color": |background_toggle|},
-        )),
+        )
         // With focus.
-        ("focus", "#source-sidebar details[open] > .files a:not(.selected)"),
-        ("wait-for-css", (
+        focus: "#source-sidebar details[open] > .files a:not(.selected)"
+        wait-for-css: (
             "#source-sidebar details[open] > .files a:not(.selected):focus",
             {"color": |color_hover|, "background-color": |background_hover|},
-        )),
-        ("focus", ".search-input"),
+        )
+        focus: ".search-input"
         // With hover.
-        ("move-cursor-to", "#source-sidebar details[open] > .files a:not(.selected)"),
-        ("assert-css", (
+        move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
+        assert-css: (
             "#source-sidebar details[open] > .files a:not(.selected):hover",
             {"color": |color_hover|, "background-color": |background_hover|},
-        )),
+        )
 
         // Without hover or focus.
-        ("assert-css", (
+        assert-css: (
             "#source-sidebar .dir-entry summary",
             {"color": |color|, "background-color": |background_toggle|},
-        )),
+        )
         // With focus.
-        ("focus", "#source-sidebar .dir-entry summary"),
-        ("wait-for-css", (
+        focus: "#source-sidebar .dir-entry summary"
+        wait-for-css: (
             "#source-sidebar .dir-entry summary:focus",
             {"color": |color_hover|, "background-color": |background_hover|},
-        )),
-        ("focus", ".search-input"),
+        )
+        focus: ".search-input"
         // With hover.
-        ("move-cursor-to", "#source-sidebar .dir-entry summary"),
-        ("assert-css", (
+        move-cursor-to: "#source-sidebar .dir-entry summary"
+        assert-css: (
             "#source-sidebar .dir-entry summary:hover",
             {"color": |color_hover|, "background-color": |background_hover|},
-        )),
+        )
 
         // Without hover or focus.
-        ("assert-css", (
+        assert-css: (
             "#source-sidebar details[open] > .folders > details > summary",
             {"color": |color|, "background-color": |background_toggle|},
-        )),
+        )
         // With focus.
-        ("focus", "#source-sidebar details[open] > .folders > details > summary"),
-        ("wait-for-css", (
+        focus: "#source-sidebar details[open] > .folders > details > summary"
+        wait-for-css: (
             "#source-sidebar details[open] > .folders > details > summary:focus",
             {"color": |color_hover|, "background-color": |background_hover|},
-        )),
-        ("focus", ".search-input"),
+        )
+        focus: ".search-input"
         // With hover.
-        ("move-cursor-to", "#source-sidebar details[open] > .folders > details > summary"),
-        ("assert-css", (
+        move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
+        assert-css: (
             "#source-sidebar details[open] > .folders > details > summary:hover",
             {"color": |color_hover|, "background-color": |background_hover|},
-        )),
-    ],
+        )
+    },
 )
 
 call-function: ("check-colors", {
@@ -171,15 +171,15 @@ assert-css: (
 
 // We now check that the scroll position is kept when opening the sidebar.
 click: "#src-sidebar-toggle"
-wait-for-css: (".sidebar", {"width": "0px"})
+wait-for-css: (".sidebar", {"left": "-1000px"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
 assert-window-property: {"pageYOffset": "2542"}
 // Expanding the sidebar...
 click: "#src-sidebar-toggle"
-wait-for-css: (".sidebar", {"width": "500px"})
+wait-for-css: (".sidebar", {"left": "0px"})
 click: "#src-sidebar-toggle"
-wait-for-css: (".sidebar", {"width": "0px"})
+wait-for-css: (".sidebar", {"left": "-1000px"})
 // The "scrollTop" property should be the same.
 assert-window-property: {"pageYOffset": "2542"}
 
index 36e4d555b8ed21ec68abfac989e875f36f3c8dee..c8a29b58d3458df5a5d2342a2c7c5b5964a1079e 100644 (file)
@@ -1,7 +1,52 @@
 // The goal of this test is to ensure that the sidebar is working as expected in the source
 // code pages.
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
-// First: desktop mode.
+show-text: true
+
+// First, check the sidebar colors.
+define-function: (
+    "check-colors",
+    (theme, color, background_color),
+    block {
+        local-storage: {
+            "rustdoc-theme": |theme|,
+            "rustdoc-use-system-theme": "false",
+        }
+        reload:
+        // Checking results colors.
+        assert-css: (".source .sidebar", {
+            "color": |color|,
+            "background-color": |background_color|
+        }, ALL)
+    },
+)
+
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "color": "rgb(197, 197, 197)",
+        "background_color": "rgb(20, 25, 31)",
+    }
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "color": "rgb(221, 221, 221)",
+        "background_color": "rgb(80, 80, 80)",
+    }
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "color": "rgb(0, 0, 0)",
+        "background_color": "rgb(245, 245, 245)",
+    }
+)
+
+// Next, desktop mode layout.
 size: (1100, 800)
 // We check that the sidebar isn't expanded and has the expected width.
 assert-css: ("nav.sidebar", {"width": "50px"})
@@ -28,15 +73,15 @@ assert: "//*[@class='dir-entry' and @open]/*[text()='sub_mod']"
 // Only "another_folder" should be "open" in "lib2".
 assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']"
 // All other trees should be collapsed.
-assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 7)
+assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 8)
 
 // We now switch to mobile mode.
 size: (600, 600)
-wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"})
+wait-for-css: (".source-sidebar-expanded nav.sidebar", {"left": "0px"})
 // We collapse the sidebar.
 click: (10, 10)
-// We check that the sidebar has the expected width (0).
-assert-css: ("nav.sidebar", {"width": "0px"})
+// We check that the sidebar has been moved off-screen.
+assert-css: ("nav.sidebar", {"left": "-1000px"})
 // We ensure that the class has been removed.
 assert-false: ".source-sidebar-expanded"
 assert: "nav.sidebar"
index 5058630f469f8711f30c9ab8014a37dcbd5c759d..9c742be0587c62a9fb09d85bf0a263f5f255d838 100644 (file)
@@ -2,6 +2,50 @@
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-property: (".sidebar", {"clientWidth": "200"})
 show-text: true
+
+// First, check the sidebar colors.
+define-function: (
+    "check-colors",
+    (theme, color, background_color),
+    block {
+        local-storage: {
+            "rustdoc-theme": |theme|,
+            "rustdoc-use-system-theme": "false",
+        }
+        reload:
+        // Checking results colors.
+        assert-css: (".sidebar", {
+            "color": |color|,
+            "background-color": |background_color|
+        }, ALL)
+    },
+)
+
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "color": "rgb(197, 197, 197)",
+        "background_color": "rgb(20, 25, 31)",
+    }
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "color": "rgb(221, 221, 221)",
+        "background_color": "rgb(80, 80, 80)",
+    }
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "color": "rgb(0, 0, 0)",
+        "background_color": "rgb(245, 245, 245)",
+    }
+)
+
 local-storage: {"rustdoc-theme": "light"}
 // We reload the page so the local storage settings are being used.
 reload:
@@ -104,4 +148,4 @@ assert-text: ("#toggle-all-docs", "[+]")
 assert-property: (".sidebar", {"clientWidth": "200"})
 click: "#toggle-all-docs"
 assert-text: ("#toggle-all-docs", "[−]")
-assert-property: (".sidebar", {"clientWidth": "200"})
\ No newline at end of file
+assert-property: (".sidebar", {"clientWidth": "200"})
index 8a33e713191292cebd0082c94858ddf0b12fe3cf..7c35119e6959dc4830c4e527253244bd023d651e 100644 (file)
@@ -22,20 +22,20 @@ assert-attribute-false: (".src-line-numbers > a:nth-child(7)", {"class": "line-h
 define-function: (
     "check-colors",
     (theme, color, background_color, highlight_color, highlight_background_color),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", (
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: (
             ".src-line-numbers > a:not(.line-highlighted)",
             {"color": |color|, "background-color": |background_color|},
             ALL,
-        )),
-        ("assert-css", (
+        )
+        assert-css: (
             ".src-line-numbers > a.line-highlighted",
             {"color": |highlight_color|, "background-color": |highlight_background_color|},
             ALL,
-        )),
-    ],
+        )
+    },
 )
 
 call-function: ("check-colors", {
@@ -102,7 +102,7 @@ assert: ".source-sidebar-expanded"
 
 // We check that the first entry of the sidebar is collapsed
 assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
-assert-text: ("#source-sidebar details:first-of-type > summary", "huge_logo")
+assert-text: ("#source-sidebar details:first-of-type > summary", "http")
 // We now click on it.
 click: "#source-sidebar details:first-of-type > summary"
 assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
@@ -111,8 +111,57 @@ assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
 click: "#source-sidebar details:first-of-type > summary"
 assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
 
-// Check the spacing.
-assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
+// And open it again, since it'll be the reference we use to check positions.
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
+
+// Check the sidebar directory entries have a marker and spacing (desktop).
+store-property: (
+    link_height,
+    "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+    "offsetHeight"
+)
+define-function: (
+    "check-sidebar-dir-entry",
+    (x, y),
+    block {
+        assert: "details:first-of-type.dir-entry[open] > summary::marker"
+        assert-css: ("#source-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})
+        // This check ensures that the summary is only one line.
+        assert-property: (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+            {"offsetHeight": |link_height|}
+        )
+        assert-position: (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+            {"x": |x|, "y": |y|}
+        )
+        assert-property: (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+            {"offsetHeight": |link_height|}
+        )
+        assert-position: (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+            // left margin
+            {"x": |x| + 27, "y": |y| + |link_height|}
+        )
+    }
+)
+store-property: (
+    source_sidebar_title_height,
+    "#source-sidebar > .title",
+    "offsetHeight"
+)
+store-property: (
+    source_sidebar_title_y,
+    "#source-sidebar > .title",
+    "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+    "x": 0,
+    // border + margin = 6
+    "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
 
 // Check the search form
 assert-css: ("nav.sub", {"flex-direction": "row"})
@@ -125,13 +174,45 @@ assert-property: ("nav.sub form", {"offsetTop": 28, "offsetHeight": 34})
 assert-property: ("#main-content", {"offsetTop": 90})
 // 28 = 90 - 34 - 28
 
-// Now do the same check on moderately-sized mobile.
+// Now do the same check on moderately-sized, tablet mobile.
 size: (700, 700)
 assert-css: ("nav.sub", {"flex-direction": "row"})
 assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
 assert-property: ("#main-content", {"offsetTop": 76})
 // 21 = 76 - 34 - 21
 
-// Tiny mobile gets a different display where the logo is stacked on top.
+// Check the sidebar directory entries have a marker and spacing (tablet).
+store-property: (
+    source_sidebar_title_height,
+    "#source-sidebar > .title",
+    "offsetHeight"
+)
+store-property: (
+    source_sidebar_title_y,
+    "#source-sidebar > .title",
+    "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+    "x": 0,
+    "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
+
+// Tiny, phone mobile gets a different display where the logo is stacked on top.
 size: (450, 700)
 assert-css: ("nav.sub", {"flex-direction": "column"})
+
+// Check the sidebar directory entries have a marker and spacing (phone).
+store-property: (
+    source_sidebar_title_height,
+    "#source-sidebar > .title",
+    "offsetHeight"
+)
+store-property: (
+    source_sidebar_title_y,
+    "#source-sidebar > .title",
+    "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+    "x": 0,
+    "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
index a5873ceb3256aa1bba532855545b43f5494fe8b8..425a3ae7e5c923a6d13e88ad9ea099e98b161da0 100644 (file)
@@ -2,13 +2,21 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "http"
+version = "0.1.0"
+
 [[package]]
 name = "implementors"
 version = "0.1.0"
+dependencies = [
+ "http",
+]
 
 [[package]]
 name = "lib2"
 version = "0.1.0"
 dependencies = [
+ "http",
  "implementors",
 ]
index 2e37f3f667a02f9ae583ede9650964a0e720d1fd..8bca77ff834d8880ba6abc30c409b0eb923c9c5f 100644 (file)
@@ -8,3 +8,4 @@ path = "lib.rs"
 
 [dependencies]
 implementors = { path = "./implementors" }
+http = { path = "./http" }
diff --git a/src/test/rustdoc-gui/src/lib2/http/Cargo.toml b/src/test/rustdoc-gui/src/lib2/http/Cargo.toml
new file mode 100644 (file)
index 0000000..fa719ef
--- /dev/null
@@ -0,0 +1,7 @@
+[package]
+name = "http"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+path = "lib.rs"
diff --git a/src/test/rustdoc-gui/src/lib2/http/lib.rs b/src/test/rustdoc-gui/src/lib2/http/lib.rs
new file mode 100644 (file)
index 0000000..204e074
--- /dev/null
@@ -0,0 +1 @@
+pub trait HttpTrait {}
index 7ef1052c49fd2e0a360336cdb241a26a4bc8e7dc..9dafc43df5f80a5860ffedc8bf80fb5c87eaf435 100644 (file)
@@ -5,3 +5,6 @@ edition = "2018"
 
 [lib]
 path = "lib.rs"
+
+[dependencies]
+http = { path = "../http/" }
index 1620e842291915ea8a8ffdc54235b2c75ad1a770..2842ac50dc1e8db54d87dd1128ed4025e706b8f4 100644 (file)
@@ -10,6 +10,8 @@ impl Whatever for Struct {
     type Foo = u8;
 }
 
+impl http::HttpTrait for Struct {}
+
 mod traits {
     pub trait TraitToReexport {
         fn method() {}
index aaed8440a40bd44807ac174149a1128732eba65e..50ba1ba62dbfae4f6b1fa6f9ff3d0600586412d5 100644 (file)
@@ -2,40 +2,40 @@
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
 define-function: (
-       "check-badge",
-       (theme, background, color),
-       [
-        ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
-               ("assert", (".docblock .stab")),
-               ("assert", (".item-table .stab")),
-               ("assert-css", (".stab", {
-                       "border-radius": "3px",
-                       "color": |color|,
-                       "background-color": |background|,
-               })),
-        ("goto", "file://" + |DOC_PATH| + "/test_docs/fn.replaced_function.html"),
-               ("assert", (".item-info .stab")),
-               ("assert-css", (".stab", {
-                       "border-radius": "3px",
-                       "color": |color|,
-                       "background-color": |background|,
-               })),
-       ]
+    "check-badge",
+    (theme, background, color),
+    block {
+        local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
+        goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+        assert: ".docblock .stab"
+        assert: ".item-table .stab"
+        assert-css: (".stab", {
+            "border-radius": "3px",
+            "color": |color|,
+            "background-color": |background|,
+        })
+        goto: "file://" + |DOC_PATH| + "/test_docs/fn.replaced_function.html"
+        assert: (".item-info .stab")
+        assert-css: (".stab", {
+            "border-radius": "3px",
+            "color": |color|,
+            "background-color": |background|,
+        })
+    },
 )
 
 call-function: ("check-badge", {
-       "theme": "ayu",
-       "color": "rgb(197, 197, 197)",
-       "background": "rgb(49, 69, 89)",
+    "theme": "ayu",
+    "color": "rgb(197, 197, 197)",
+    "background": "rgb(49, 69, 89)",
 })
 call-function: ("check-badge", {
-       "theme": "dark",
-       "color": "rgb(221, 221, 221)",
-       "background": "rgb(49, 69, 89)",
+    "theme": "dark",
+    "color": "rgb(221, 221, 221)",
+    "background": "rgb(49, 69, 89)",
 })
 call-function: ("check-badge", {
-       "theme": "light",
-       "color": "rgb(0, 0, 0)",
-       "background": "rgb(255, 245, 214)",
+    "theme": "light",
+    "color": "rgb(0, 0, 0)",
+    "background": "rgb(255, 245, 214)",
 })
index 3e5c30dc7eafe47f9546850b4737ad7d5cf7a757..ca393ee58917dd0a950f3e3ad0593b1fd536913d 100644 (file)
@@ -8,14 +8,14 @@ assert: "#method\.a_method:target"
 define-function: (
     "check-style",
     (theme, background, border),
-    [
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
-        ("reload"),
-        ("assert-css", ("#method\.a_method:target", {
+    block {
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
+        reload:
+        assert-css: ("#method\.a_method:target", {
             "background-color": |background|,
             "border-right": "3px solid " + |border|,
-        })),
-    ],
+        })
+    },
 )
 
 call-function: ("check-style", {
index 45bb8daf1f20c575bc4bb0414e8c664b44a4b73b..89ce78e3aab4b6274081590cd29ab47dd1adf0c1 100644 (file)
@@ -50,24 +50,24 @@ show-text: true
 define-function: (
     "check-color",
     (theme, filter),
-    [
+    block {
         // Setting the theme.
-       ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
+        reload:
 
-        ("assert-css", ("details.rustdoc-toggle > summary::before", {
+        assert-css: ("details.rustdoc-toggle > summary::before", {
             "opacity": "0.5",
             "filter": |filter|,
-        }, ALL)),
-        ("move-cursor-to", "details.rustdoc-toggle summary"),
-        ("assert-css", ("details.rustdoc-toggle > summary:hover::before", {
+        }, ALL)
+        move-cursor-to: "details.rustdoc-toggle summary"
+        assert-css: ("details.rustdoc-toggle > summary:hover::before", {
             "opacity": "1",
             "filter": |filter|,
-        })),
+        })
         // moving the cursor somewhere else to not mess with next function calls.
-        ("move-cursor-to", ".search-input"),
-    ]
+        move-cursor-to: ".search-input"
+    },
 )
 
 call-function: ("check-color", {"theme": "ayu", "filter": "invert(1)"})
index c014eb52e710030804cf955916e18ad238181ea1..9b60bc04738bfe542da46e5fc8d048c806743059 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-tidy-linelength
 // This test ensures that the items declaration content overflow is handled inside the <pre> directly.
 
 // We need to disable this check because
index 5e43b85fce08410eecf07e4ec32af48ecda6fa97..d3a672ddde6e491250e4022c1c7a1a5ee3be4bbc 100644 (file)
@@ -14,13 +14,13 @@ define-function: (
     // `theme` is the theme being tested.
     // `color` is the expected color of the `<sup>` element.
     (theme, color),
-    [
+    block {
         // Set the theme.
-        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
         // We reload the page so the local storage settings are being used.
-        ("reload"),
-        ("assert-css", (".item-left sup", {"color": |color|})),
-    ],
+        reload:
+        assert-css: (".item-left sup", {"color": |color|})
+    },
 )
 
 call-function: ("sup-check", ("dark", "rgb(221, 221, 221)"))
index 6573166c47f222c41235de6726caa27d525da8bf..0d2c6b2209bd1c9fbcfca2eb2b6099164992db84 100644 (file)
@@ -14,7 +14,8 @@ pub mod builders {
     }
 }
 
-// @count "$.index[*][?(@.name=='builders')]" 2
+// @count "$.index[*][?(@.name=='builders')]" 1
+// @has "$.index[*][?(@.name == 'ActionRowBuilder')"]
 pub use auto::*;
 
 pub mod builders {
index 8c221615aa753ebc9b38ee9f480af7fe10881bed..06906df3b2c64abed8e5e711db781e987d32d270 100644 (file)
@@ -1,12 +1,12 @@
 #[repr(i8)]
 pub enum Ordering {
-    // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
-    // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"'
     Less = -1,
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"'
     Equal = 0,
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"'
     Greater = 1,
 }
index 235b0b47381fce51acaac7d2c1163b23b7eb1951..e639965e79b428e180ed94a959dd3d5219e10365 100644 (file)
@@ -1,30 +1,30 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"'
     Addition = 0 + 0,
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"'
     Bin = 0b1,
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"'
     Oct = 0o2,
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"'
     PubConst = THREE,
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"'
     Hex = 0x4,
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"'
     Cast = 5 as isize,
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"'
     PubCall = six(),
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"'
     PrivCall = seven(),
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"'
     PrivConst = EIGHT,
 }
 
index 8df73d78d237fd2e09cd2deccd8a90dee5bfb821..e56d5594f2fc915730be2531d85e2f47e43fa20d 100644 (file)
@@ -4,40 +4,40 @@
 
 #[repr(u64)]
 pub enum U64 {
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.expr" '"u64::MIN"'
     U64Min = u64::MIN,
-    // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
-    // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.expr" '"u64::MAX"'
     U64Max = u64::MAX,
 }
 
 #[repr(i64)]
 pub enum I64 {
-    // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
-    // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.expr" '"i64::MIN"'
     I64Min = i64::MIN,
-    // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
-    // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.expr" '"i64::MAX"'
     I64Max = i64::MAX,
 }
 
 #[repr(u128)]
 pub enum U128 {
-    // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.expr" '"u128::MIN"'
     U128Min = u128::MIN,
-    // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
-    // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.expr" '"u128::MAX"'
     U128Max = u128::MAX,
 }
 
 #[repr(i128)]
 pub enum I128 {
-    // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
-    // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.expr" '"i128::MIN"'
     I128Min = i128::MIN,
-    // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
-    // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.expr" '"i128::MAX"'
     I128Max = i128::MAX,
 }
index 3417baa0760e1a76cc5a71a6af54357dc987c84c..6889b305ffb41b32c475100bfe62afd7ad5b86ad 100644 (file)
@@ -1,15 +1,15 @@
 #[repr(u32)]
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"'
     Basic = 0,
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"'
     Suffix = 10u32,
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.expr" '"1_0_0"'
     Underscore = 1_0_0,
-    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
-    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.expr" '"1_0_0_0u32"'
     SuffixUnderscore = 1_0_0_0u32,
 }
index 6af944a2219ef6f4c7f0dad91c13da9ca95f3022..6a4f54de617454a7528bc299db0e0edf81439d6c 100644 (file)
@@ -1,10 +1,10 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+    // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}'
     Has = 0,
-    // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null
     Doesnt,
-    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null
     AlsoDoesnt,
-    // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+    // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}'
     AlsoHas = 44,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/struct.rs b/src/test/rustdoc-json/enums/discriminant/struct.rs
new file mode 100644 (file)
index 0000000..e91a632
--- /dev/null
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(i32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Struct')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0
+    Struct {},
+    // @is    "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}'
+    // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1
+    StructWithDiscr { x: i32 } = 42,
+    // @is    "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant"  '{"expr": "0x42", "value": "66"}'
+    // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2
+    StructWithHexDiscr { x: i32, y: bool } = 0x42,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/tuple.rs b/src/test/rustdoc-json/enums/discriminant/tuple.rs
new file mode 100644 (file)
index 0000000..b94d573
--- /dev/null
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(u32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Tuple')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0
+    Tuple(),
+    // @is    "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}'
+    // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1
+    TupleWithDiscr(i32) = 1,
+    // @is    "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}'
+    // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2
+    TupleWithBinDiscr(i32, i32) = 0b10,
+}
index e6310cc3b997c28860234fd3c461596c8ec9ada7..78a05431472cb8874cc80439fbc0e973ab18d506 100644 (file)
@@ -5,8 +5,8 @@
 
 // @has "$.index[*][?(@.name=='ParseError')]"
 // @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null
 
 pub enum ParseError {
     UnexpectedEndTag(#[doc(hidden)] u32),
index e9ea3ae23c226808ff861878613b359aca050163..1787a859c8b37c8fb4afb11d80e25dca246f960e 100644 (file)
@@ -5,27 +5,22 @@
 
 pub enum Foo {
     // @set Unit = "$.index[*][?(@.name=='Unit')].id"
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"'
     Unit,
     // @set Named = "$.index[*][?(@.name=='Named')].id"
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+    // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}'
     Named {},
     // @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+    // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" []
     Tuple(),
     // @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
     // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false
     NamedField { x: i32 },
     // @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
     // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+    // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field
     TupleField(i32),
 }
 
index f612a34a4927744b55462662c7ee457aef6fa5cf..de939cde2e7b34b990736d3664a39dca6202e0b8 100644 (file)
@@ -9,9 +9,8 @@ pub enum Foo {
         // @set y = "$.index[*][?(@.name=='y')].id"
         y: i32,
     },
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
-    // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y
+    // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2
 }
index f546eaa0d172df6beb83ecba8d83f213318f50b2..70bfbb81826bee450acfcc2018d34da3661e449a 100644 (file)
 // @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
 
 pub enum EnumWithStrippedTupleVariants {
-    // @is    "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+    // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0
     None(),
 
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+    // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0
     One(/** 1.1.0*/ bool),
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+    // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null
     OneHidden(#[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+    // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1
     Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1
     TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null
     TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null
     TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+    // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2
     Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+    // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2
     Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+    // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null
     Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
 }
 
-
 // @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
index 23b854d8d1721a1c05db3bcd017fe442a757c475..bc870c502a0112b0f801495c15ac061b9ae83870 100644 (file)
@@ -1,11 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
-    // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
     // @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @set x = "$.index[*][?(@.name=='x')].id"
     // @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
-    VariantS {
-        x: u32,
-        y: String,
-    },
+    // @set y = "$.index[*][?(@.name=='y')].id"
+    // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y
+    VariantS { x: u32, y: String },
 }
index b71ec47a804ad961c1da11f06f86a6b71497c6fc..d1207bbfb18da6213394c8f8712c63affd83332a 100644 (file)
@@ -1,8 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
-    // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
     // @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @set f0 = "$.index[*][?(@.name=='0')].id"
     // @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+    // @set f1 = "$.index[*][?(@.name=='1')].id"
+    // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1
     VariantA(u32, String),
 }
diff --git a/src/test/rustdoc-json/primitives/local_primitive.rs b/src/test/rustdoc-json/primitives/local_primitive.rs
new file mode 100644 (file)
index 0000000..f27e6a2
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/104064>.
+
+#![feature(no_core)]
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![no_core]
+#![rustc_coherence_is_core]
+
+//! Link to [i32][prim@i32] [i64][prim@i64]
+
+#[doc(primitive = "i32")]
+mod prim_i32 {}
+
+// @set local_i32 = "$.index[*][?(@.name=='i32')].id"
+
+// @has "$.index[*][?(@.name=='local_primitive')]"
+// @ismany "$.index[*][?(@.name=='local_primitive')].inner.items[*]" $local_i32
+// @is "$.index[*][?(@.name=='local_primitive')].links['prim@i32']" $local_i32
+
+// Let's ensure the `prim_i32` module isn't present in the output JSON:
+// @!has "$.index[*][?(@.name=='prim_i32')]"
diff --git a/src/test/rustdoc-json/reexport/pub_use_doc_hidden.rs b/src/test/rustdoc-json/reexport/pub_use_doc_hidden.rs
new file mode 100644 (file)
index 0000000..a2a25d0
--- /dev/null
@@ -0,0 +1,15 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/106379>
+
+#![feature(no_core)]
+#![no_core]
+
+mod repeat_n {
+    #[doc(hidden)]
+    pub struct RepeatN {}
+}
+
+pub use repeat_n::RepeatN;
+
+// @count "$.index[*][?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0
+// @!has "$.index[*][?(@.kind=='struct')]"
+// @!has "$.index[*][?(@.kind=='import')]"
diff --git a/src/test/rustdoc-ui/issue-105334.rs b/src/test/rustdoc-ui/issue-105334.rs
new file mode 100644 (file)
index 0000000..ee1adc6
--- /dev/null
@@ -0,0 +1,2 @@
+impl Vec< br##"*.."## > {}
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-105334.stderr b/src/test/rustdoc-ui/issue-105334.stderr
new file mode 100644 (file)
index 0000000..e163bb4
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105334.rs:1:11
+   |
+LL | impl Vec< br##"*.."## > {}
+   |           ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105737.rs b/src/test/rustdoc-ui/issue-105737.rs
new file mode 100644 (file)
index 0000000..154f069
--- /dev/null
@@ -0,0 +1,4 @@
+impl Vec<lol> {}
+//~^ ERROR
+
+pub fn lol() {}
diff --git a/src/test/rustdoc-ui/issue-105737.stderr b/src/test/rustdoc-ui/issue-105737.stderr
new file mode 100644 (file)
index 0000000..2dd9beb
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105737.rs:1:10
+   |
+LL | impl Vec<lol> {}
+   |          ^^^
+   |
+   = help: `lol` is a function item, not a type
+   = help: function item types cannot be named directly
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105742.rs b/src/test/rustdoc-ui/issue-105742.rs
new file mode 100644 (file)
index 0000000..cb1de74
--- /dev/null
@@ -0,0 +1,40 @@
+// compile-flags: -Znormalize-docs
+
+use std::ops::Index;
+
+pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+    let _ = s;
+}
+
+pub trait SVec: Index<
+    <Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Index<<Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Self as SVec>::Item> as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+//~^^^^^^^^ ERROR
+> {
+    type Item<'a, T>;
+
+    fn len(&self) -> <Self as SVec>::Item;
+    //~^ ERROR
+    //~^^ ERROR
+    //~^^^ ERROR
+    //~^^^^ ERROR
+}
diff --git a/src/test/rustdoc-ui/issue-105742.stderr b/src/test/rustdoc-ui/issue-105742.stderr
new file mode 100644 (file)
index 0000000..ffb602c
--- /dev/null
@@ -0,0 +1,385 @@
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                         ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                         +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                         ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                         +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                                  ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                                  +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                                  ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                                  +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) {
+   |                                            ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) {
+   |                                            +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                         ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                         +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                         ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                         +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                                  ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                                  +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                                  ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                                  +++
+
+error[E0038]: the trait `SVec` cannot be made into an object
+  --> $DIR/issue-105742.rs:5:31
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-105742.rs:12:17
+   |
+LL |    pub trait SVec: Index<
+   |  ____________----__^
+   | |            |
+   | |            this trait cannot be made into an object...
+LL | |      <Self as SVec>::Item,
+LL | |
+LL | |
+...  |
+LL | |/     Output = <Index<<Self as SVec>::Item,
+LL | ||
+LL | ||
+LL | ||
+LL | ||
+LL | ||     Output = <Self as SVec>::Item> as SVec>::Item,
+   | ||_________________________________________________^ ...because it uses `Self` as a type parameter
+...  |
+LL | |
+LL | |  > {
+   | |__^ ...because it uses `Self` as a type parameter
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                          ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                          +++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                          ++++
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                          +++
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/rustdoc-ui/issue-106213.rs b/src/test/rustdoc-ui/issue-106213.rs
new file mode 100644 (file)
index 0000000..6d51846
--- /dev/null
@@ -0,0 +1,7 @@
+// compile-flags: --document-private-items
+// edition:2021
+
+fn use_avx() -> dyn  {
+    //~^ ERROR at least one trait is required for an object type
+    !( ident_error )
+}
diff --git a/src/test/rustdoc-ui/issue-106213.stderr b/src/test/rustdoc-ui/issue-106213.stderr
new file mode 100644 (file)
index 0000000..0a4ff69
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/issue-106213.rs:4:17
+   |
+LL | fn use_avx() -> dyn  {
+   |                 ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/rustdoc-ui/issue-106226.rs b/src/test/rustdoc-ui/issue-106226.rs
new file mode 100644 (file)
index 0000000..71b497a
--- /dev/null
@@ -0,0 +1,3 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106226>.
+type F = [_; ()];
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-106226.stderr b/src/test/rustdoc-ui/issue-106226.stderr
new file mode 100644 (file)
index 0000000..2beffbc
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-106226.rs:2:14
+   |
+LL | type F = [_; ()];
+   |              ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/rustdoc-ui/issue-96287.rs b/src/test/rustdoc-ui/issue-96287.rs
new file mode 100644 (file)
index 0000000..8d8b445
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait TraitWithAssoc {
+    type Assoc;
+}
+
+pub type Foo<V> = impl Trait<V::Assoc>;
+//~^ ERROR
+//~^^ ERROR
+
+pub trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+pub fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+    ()
+}
diff --git a/src/test/rustdoc-ui/issue-96287.stderr b/src/test/rustdoc-ui/issue-96287.stderr
new file mode 100644 (file)
index 0000000..0236b9f
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
index 53677b18377098bbf77089472e3a1d8513528c21..537dc92be192101237c068f44fe856b9ac4f5cb0 100644 (file)
@@ -8,7 +8,6 @@
     -Z                       branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
     -Z                           cf-protection=val -- instrument control-flow architecture protection
     -Z               cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
-    -Z                                   chalk=val -- enable the experimental Chalk-based trait solving engine
     -Z                         codegen-backend=val -- the backend to use
     -Z                             combine-cgu=val -- combine CGUs into a single one
     -Z                              crate-attr=val -- inject the given attribute in the crate
@@ -35,7 +34,8 @@
     -Z            dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
     -Z                       dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
     -Z                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
-    -Z                         dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
+    -Z                         dump-mono-stats=val -- output statistics about monomorphization collection
+    -Z                  dump-mono-stats-format=val -- the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
     -Z                               dylib-lto=val -- enables LTO for dylib crate type
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                               tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
     -Z                            trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
     -Z                       track-diagnostics=val -- tracks where in rustc a diagnostic was emitted
+    -Z                            trait-solver=val -- specify the trait solver mode used by rustc (default: classic)
     -Z                translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
     -Z        translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
     -Z                          translate-lang=val -- language identifier for diagnostic output
index 0277501de097f956517d1ae6c14d33d89ea0e30f..af765c51ace391da7ea7608e5d85b46f9d9939af 100644 (file)
@@ -59,7 +59,7 @@ pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
 // @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str'
 pub async fn elided(foo: &str) -> &str {}
 // This should really be shown as written, but for implementation reasons it's difficult.
-// See `impl Clean for TyKind::Rptr`.
+// See `impl Clean for TyKind::Ref`.
 // @has async_fn/fn.user_elided.html
 // @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str'
 pub async fn user_elided(foo: &'_ str) -> &str {}
index 353ce10243e0055d8ee570b77bf4d9f8e786d076..7a6c733d464ce9d38b3b78306c3cd5628ab5793d 100644 (file)
@@ -7,6 +7,11 @@
 #[path = "src-links/mod.rs"]
 pub mod qux;
 
+// @has src/foo/src-links.rs.html
+// @has foo/fizz/index.html '//a/@href' '../src/foo/src-links/fizz.rs.html'
+#[path = "src-links/../src-links/fizz.rs"]
+pub mod fizz;
+
 // @has foo/bar/index.html '//a/@href' '../../src/foo/src-links.rs.html'
 pub mod bar {
 
diff --git a/src/test/rustdoc/src-links/fizz.rs b/src/test/rustdoc/src-links/fizz.rs
new file mode 100644 (file)
index 0000000..d2b76b1
--- /dev/null
@@ -0,0 +1 @@
+pub struct Buzz;
index a4b911878e0d6c4866811b697159d0b923212ced..1c376f59e5174a4d82654d5724de868e39e933e9 100644 (file)
@@ -6,6 +6,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
index 580c85f9b7848fcaad34d060c827e2c7a5e4cc8e..844d40f2ecd6a4590500b18a1727df21d8dbbca9 100644 (file)
@@ -8,6 +8,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
index 921767af981ad6e10062da418868ba91ad99a3c9..214bb4368ffdd808aba26eeb77b533fd77bd339c 100644 (file)
@@ -5,6 +5,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 mod submod {
     use rustc_macros::{Decodable, Encodable};
 
index 8486b8b6e481a3e300696e90f800fd962100a0cc..e1084a08fec93f0baf472ca8bbe16f447cdc528f 100644 (file)
@@ -7,6 +7,11 @@
 
 use rustc_macros::{Decodable, Encodable};
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 pub const other: u8 = 1;
 pub const f: u8 = 1;
 pub const d: u8 = 1;
index 187f9a24a9075fff3ca5db4e7a1270bb38e2bb84..ffad80171da7798645608a04194101cdcb475b90 100644 (file)
 
 extern crate rustc_arena;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_arena::TypedArena;
 
 trait HasId { fn count(&self) -> usize; }
index 6e5eb54629ccde87b9ce5437b39fd819197e2657..10e8beaa7b119d944d9e4a6bad24a2538dd75f5c 100644 (file)
@@ -6,6 +6,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
index 215dfaed7abbef1b70390efd40c74a97e5abb390..309b5c4a03d57c3b3f0e1e95561720dc60129936 100644 (file)
@@ -7,6 +7,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
diff --git a/src/test/ui-fulldeps/missing-rustc-driver-error.rs b/src/test/ui-fulldeps/missing-rustc-driver-error.rs
new file mode 100644 (file)
index 0000000..654cd6f
--- /dev/null
@@ -0,0 +1,11 @@
+// Test that we get the following hint when trying to use a compiler crate without rustc_driver.
+// error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate
+// compile-flags: --emit link
+// The exactly list of required crates depends on the target. as such only test Unix targets.
+// only-unix
+
+#![feature(rustc_private)]
+
+extern crate rustc_serialize;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/missing-rustc-driver-error.stderr b/src/test/ui-fulldeps/missing-rustc-driver-error.stderr
new file mode 100644 (file)
index 0000000..ad03ba0
--- /dev/null
@@ -0,0 +1,24 @@
+error: crate `rustc_serialize` required to be available in rlib format, but was not found in this form
+   |
+   = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
+error: crate `smallvec` required to be available in rlib format, but was not found in this form
+
+error: crate `thin_vec` required to be available in rlib format, but was not found in this form
+
+error: crate `indexmap` required to be available in rlib format, but was not found in this form
+
+error: crate `hashbrown` required to be available in rlib format, but was not found in this form
+
+error: crate `ahash` required to be available in rlib format, but was not found in this form
+
+error: crate `once_cell` required to be available in rlib format, but was not found in this form
+
+error: crate `getrandom` required to be available in rlib format, but was not found in this form
+
+error: crate `cfg_if` required to be available in rlib format, but was not found in this form
+
+error: crate `libc` required to be available in rlib format, but was not found in this form
+
+error: aborting due to 10 previous errors
+
index bb246de0e572dd4aa65f7a92f33ec63303ce9b19..ff1be0804151b58973c1a41c5616e7a3cc5f73df 100644 (file)
 extern crate rustc_session;
 extern crate rustc_span;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::FilePathMapping;
index a93ba87470a9c045703a8d31a2d39b51884d04a5..6dbabc8eb348512d437c60bbd9aad8113017310e 100644 (file)
 extern crate rustc_span;
 extern crate thin_vec;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::*;
index 30e62723240681ea2b1d767990a02d4776c2b5a3..63975ef62c591f422762d233682fd092b92a4e81 100644 (file)
 extern crate rustc_arena;
 extern crate libc;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use TypeStructure::{TypeInt, TypeFunction};
 use AstKind::{ExprInt, ExprVar, ExprLambda};
 use rustc_arena::TypedArena;
index 452110a65e4aa18ac966be2213c89c5b4a921696..509a6b1d22ca61769fc0cc714e64b20cd3014db5 100644 (file)
@@ -6,6 +6,11 @@
 #[allow(dead_code)]
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 
 #[derive(Decodable, Encodable, Debug)]
index dd3665f22ac7880503376a2d726fbc8072c03aa7..59192a1ecc3f493a8a3e34f93583fe00a94680bf 100644 (file)
@@ -3,10 +3,7 @@ error[E0308]: mismatched types
    |
 LL |    #[alloc_error_handler]
    |    ---------------------- in this procedural macro expansion
-LL |    fn oom(
-   |  __^
-   | | _|
-   | ||
+LL | // fn oom(
 LL | ||     info: &Layout,
 LL | || ) -> ()
    | ||_______- arguments to this function are incorrect
@@ -29,10 +26,7 @@ error[E0308]: mismatched types
    |
 LL |    #[alloc_error_handler]
    |    ---------------------- in this procedural macro expansion
-LL |    fn oom(
-   |  __^
-   | | _|
-   | ||
+LL | // fn oom(
 LL | ||     info: &Layout,
 LL | || ) -> ()
    | ||_______^ expected `!`, found `()`
index 2673ee9f937fb1e87bee5d6ebf36c177d097622b..7d23c2fc05ac3d9d086c91fb928f15a8f8f2bd56 100644 (file)
@@ -3,10 +3,7 @@ error[E0308]: mismatched types
    |
 LL |    #[alloc_error_handler]
    |    ---------------------- in this procedural macro expansion
-LL |    fn oom(
-   |  __^
-   | | _|
-   | ||
+LL | // fn oom(
 LL | ||     info: Layout,
 LL | || ) {
    | ||_- arguments to this function are incorrect
@@ -36,10 +33,7 @@ error[E0308]: mismatched types
    |
 LL |    #[alloc_error_handler]
    |    ---------------------- in this procedural macro expansion
-LL |    fn oom(
-   |  __^
-   | | _|
-   | ||
+LL | // fn oom(
 LL | ||     info: Layout,
 LL | || ) {
    | ||_^ expected `!`, found `()`
index 8430fabe84d0962dbeb17ca26afaa414b764100e..ea9ad39a70d81d2b6db694dcc56d406a2dcca461 100644 (file)
@@ -7,7 +7,7 @@
 struct Layout;
 
 #[alloc_error_handler]
-fn oom() -> ! { //~ ERROR this function takes 0 arguments but 1 argument was supplied
+fn oom() -> ! { //~ ERROR function takes 0 arguments but 1 argument was supplied
     loop {}
 }
 
index 3e96322d67efb815cbf227a383db2b0e0d4afd23..961e7a50e56381129abb247f3ae8023674b22a0b 100644 (file)
@@ -18,11 +18,11 @@ fn permuted(_x: X, _y: Y, _z: Z) {}
 
 fn main() {
     invalid(1.0); //~ ERROR mismatched types
-    extra(""); //~ ERROR this function takes
-    missing(); //~ ERROR this function takes
+    extra(""); //~ ERROR function takes
+    missing(); //~ ERROR function takes
     swapped("", 1); //~ ERROR arguments to this function are incorrect
     permuted(Y {}, Z {}, X {}); //~ ERROR arguments to this function are incorrect
 
     let closure = |x| x;
-    closure(); //~ ERROR this function takes
+    closure(); //~ ERROR function takes
 }
index d765bc4f74d332c71bf301de9a4e849e477282a9..acb61f543088a5062ca9bc7387b99fb8839ecd05 100644 (file)
@@ -4,5 +4,5 @@ fn foo(x: &(dyn Display + Send)) {}
 
 fn main() {
     foo();
-    //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+    //~^ ERROR function takes 1 argument but 0 arguments were supplied
 }
index a18e967668deff0d7180d45d3731d240900e0252..569a39a2b450dbbe10c46e2f5b0658900b0723b1 100644 (file)
@@ -1,11 +1,11 @@
 fn foo<T: Fn()>(t: T) {
     t(1i32);
-    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+    //~^ ERROR function takes 0 arguments but 1 argument was supplied
 }
 
 fn bar(t: impl Fn()) {
     t(1i32);
-    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+    //~^ ERROR function takes 0 arguments but 1 argument was supplied
 }
 
 fn baz() -> impl Fn() {
@@ -14,13 +14,13 @@ fn baz() -> impl Fn() {
 
 fn baz2() {
     baz()(1i32)
-    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+    //~^ ERROR function takes 0 arguments but 1 argument was supplied
 }
 
 fn qux() {
     let x = || {};
     x(1i32);
-    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+    //~^ ERROR function takes 0 arguments but 1 argument was supplied
 }
 
 fn main() {}
diff --git a/src/test/ui/argument-suggestions/extern-fn-arg-names.rs b/src/test/ui/argument-suggestions/extern-fn-arg-names.rs
new file mode 100644 (file)
index 0000000..df2fd66
--- /dev/null
@@ -0,0 +1,9 @@
+extern "Rust" {
+    fn dstfn(src: i32, dst: err);
+    //~^ ERROR cannot find type `err` in this scope
+}
+
+fn main() {
+    dstfn(1);
+    //~^ ERROR function takes 2 arguments but 1 argument was supplied
+}
diff --git a/src/test/ui/argument-suggestions/extern-fn-arg-names.stderr b/src/test/ui/argument-suggestions/extern-fn-arg-names.stderr
new file mode 100644 (file)
index 0000000..f6bc84c
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0412]: cannot find type `err` in this scope
+  --> $DIR/extern-fn-arg-names.rs:2:29
+   |
+LL |     fn dstfn(src: i32, dst: err);
+   |                             ^^^ not found in this scope
+
+error[E0061]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/extern-fn-arg-names.rs:7:5
+   |
+LL |     dstfn(1);
+   |     ^^^^^--- an argument is missing
+   |
+note: function defined here
+  --> $DIR/extern-fn-arg-names.rs:2:8
+   |
+LL |     fn dstfn(src: i32, dst: err);
+   |        ^^^^^
+help: provide the argument
+   |
+LL |     dstfn(1, /* dst */);
+   |          ~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0061, E0412.
+For more information about an error, try `rustc --explain E0061`.
index 3706ac4e8e18d1b0fd61d8b4efc356f8f9cdc848..3f83de95e2d549cfdf4f1b4fd4426419517af23a 100644 (file)
@@ -4,30 +4,30 @@ fn two_arg_same(_a: i32, _b: i32) {}
 fn two_arg_diff(_a: i32, _b: &str) {}
 
 fn main() {
-  empty(""); //~ ERROR this function takes
+  empty(""); //~ ERROR function takes
 
-  one_arg(1, 1); //~ ERROR this function takes
-  one_arg(1, ""); //~ ERROR this function takes
-  one_arg(1, "", 1.0); //~ ERROR this function takes
+  one_arg(1, 1); //~ ERROR function takes
+  one_arg(1, ""); //~ ERROR function takes
+  one_arg(1, "", 1.0); //~ ERROR function takes
 
-  two_arg_same(1, 1, 1); //~ ERROR this function takes
-  two_arg_same(1, 1, 1.0); //~ ERROR this function takes
+  two_arg_same(1, 1, 1); //~ ERROR function takes
+  two_arg_same(1, 1, 1.0); //~ ERROR function takes
 
-  two_arg_diff(1, 1, ""); //~ ERROR this function takes
-  two_arg_diff(1, "", ""); //~ ERROR this function takes
-  two_arg_diff(1, 1, "", ""); //~ ERROR this function takes
-  two_arg_diff(1, "", 1, ""); //~ ERROR this function takes
+  two_arg_diff(1, 1, ""); //~ ERROR function takes
+  two_arg_diff(1, "", ""); //~ ERROR function takes
+  two_arg_diff(1, 1, "", ""); //~ ERROR function takes
+  two_arg_diff(1, "", 1, ""); //~ ERROR function takes
 
   // Check with weird spacing and newlines
-  two_arg_same(1, 1,     ""); //~ ERROR this function takes
-  two_arg_diff(1, 1,     ""); //~ ERROR this function takes
-  two_arg_same( //~ ERROR this function takes
+  two_arg_same(1, 1,     ""); //~ ERROR function takes
+  two_arg_diff(1, 1,     ""); //~ ERROR function takes
+  two_arg_same( //~ ERROR function takes
     1,
     1,
     ""
   );
 
-  two_arg_diff( //~ ERROR this function takes
+  two_arg_diff( //~ ERROR function takes
     1,
     1,
     ""
index 4446b4bc2fcf341435ba0e13e78f0beea0a4c3e4..fb0af05e9dc553cf3509a70564aa61a0e1978e3a 100644 (file)
@@ -2,6 +2,6 @@ fn foo(i: impl std::fmt::Display) {}
 
 fn main() {
     foo::<()>(());
-    //~^ ERROR this function takes 0 generic arguments but 1 generic argument was supplied
+    //~^ ERROR function takes 0 generic arguments but 1 generic argument was supplied
     //~| ERROR `()` doesn't implement `std::fmt::Display`
 }
index 6bef6ad103862dec8f851e7c1cdd4878f03c2b17..fb50fa115376b3a9a6a9eb08d042aadbdcc9a1dc 100644 (file)
@@ -31,7 +31,7 @@ fn three_diff(_a: T1, _b: T2, _c: T3) {}
 fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {}
 
 fn main() {
-    three_diff(T2::new(0)); //~ ERROR this function takes
+    three_diff(T2::new(0)); //~ ERROR function takes
     four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308]
     four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308]
 
index 7994d3cd9959cb469d9aa33cd269667c732a2926..25f7f58379923cc53a6d29a464649e2f91bf9df3 100644 (file)
@@ -13,7 +13,7 @@ fn f(
 ) {}
 
 fn main() {
-    f(C, A, A, A, B, B, C); //~ ERROR this function takes 6 arguments but 7 arguments were supplied [E0061]
+    f(C, A, A, A, B, B, C); //~ ERROR function takes 6 arguments but 7 arguments were supplied [E0061]
     f(C, C, A, A, B, B);  //~ ERROR arguments to this function are incorrect [E0308]
     f(A, A, D, D, B, B);  //~ arguments to this function are incorrect [E0308]
     f(C, C, B, B, A, A);  //~ arguments to this function are incorrect [E0308]
index 9c6e81ab8cc75eb5b292c15fc7a7f9bff760bc8e..5e720f174c24015ea652077854103afb24c152ad 100644 (file)
@@ -5,5 +5,5 @@ fn arg<T>() -> T { todo!() }
 fn main() {
     let x = arg(); // `x` must be inferred
     // The reference on `&x` is important to reproduce the ICE
-    f(&x, ""); //~ ERROR this function takes 3 arguments but 2 arguments were supplied
+    f(&x, ""); //~ ERROR function takes 3 arguments but 2 arguments were supplied
 }
index 6f9f4293e49643d0ce312a24d805e3d3e4cb99fd..4c22608ae6a476ca2420057d94a7f0e6bcdbdb84 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {
     g((), ());
-    //~^ ERROR this function takes 6 arguments but 2 arguments were supplied
+    //~^ ERROR function takes 6 arguments but 2 arguments were supplied
 }
 
 pub fn g(a1: (), a2: bool, a3: bool, a4: bool, a5: bool, a6: ()) -> () {}
index bb383ab1f8b9ebe066676e5c7526ff875d5ec737..9e537b0c35f96bceb3cd3a86f3e41431d5a5b594 100644 (file)
@@ -10,5 +10,5 @@ fn foo(a: &A, d: D, e: &E, g: G) {}
 
 fn main() {
     foo(&&A, B, C, D, E, F, G);
-    //~^ ERROR this function takes 4 arguments but 7 arguments were supplied
+    //~^ ERROR function takes 4 arguments but 7 arguments were supplied
 }
index c2618a96716a5672fcfb0adbdcd443a12e6c6a00..e421eba97758e6de8ede6363c69b049043f33d40 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
     (|_, ()| ())(if true {} else {return;});
-    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+    //~^ ERROR function takes 2 arguments but 1 argument was supplied
 }
index c55f495d69862a6537e5db3ff3f0e6e3092638fa..27734f74dee78420506485adbcce02342a691c9c 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
     (|_, ()| ())([return, ()]);
-    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+    //~^ ERROR function takes 2 arguments but 1 argument was supplied
 }
index 731b863069b23d7283af4f129e48f3f782afa607..7bbb39f8d62e2824d43b48cc22f89697e0acd625 100644 (file)
@@ -1,5 +1,5 @@
 fn main() {
     let f = |_: (), f: fn()| f;
     let _f = f(main);
-    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+    //~^ ERROR function takes 2 arguments but 1 argument was supplied
 }
index ae0dabf27b1968f90ae25c415b0c3257bcb755be..c26564641cb9f77b72b4f54a0c880b9e84079e61 100644 (file)
@@ -7,34 +7,34 @@ fn four_repeated(_a: i32, _b: f32, _c: f32, _d: &str) {}
 fn complex(_a: i32, _b: f32, _c: i32, _d: f32, _e: &str) {}
 
 fn main() {
-  one_arg(); //~ ERROR this function takes
+  one_arg(); //~ ERROR function takes
   // The headers here show the types expected,
   // with formatting to emphasize which arguments are missing
   /*         i32     f32    */
-  two_same(               ); //~ ERROR this function takes
-  two_same(   1           ); //~ ERROR this function takes
-  two_diff(               ); //~ ERROR this function takes
-  two_diff(   1           ); //~ ERROR this function takes
-  two_diff(          1.0  ); //~ ERROR this function takes
+  two_same(               ); //~ ERROR function takes
+  two_same(   1           ); //~ ERROR function takes
+  two_diff(               ); //~ ERROR function takes
+  two_diff(   1           ); //~ ERROR function takes
+  two_diff(          1.0  ); //~ ERROR function takes
 
   /*           i32     i32     i32    */
-  three_same(                       ); //~ ERROR this function takes
-  three_same(   1                   ); //~ ERROR this function takes
-  three_same(   1,      1           ); //~ ERROR this function takes
+  three_same(                       ); //~ ERROR function takes
+  three_same(   1                   ); //~ ERROR function takes
+  three_same(   1,      1           ); //~ ERROR function takes
 
   /*           i32     f32     &str   */
-  three_diff(          1.0,     ""  ); //~ ERROR this function takes
-  three_diff(   1,              ""  ); //~ ERROR this function takes
-  three_diff(   1,     1.0          ); //~ ERROR this function takes
-  three_diff(                   ""  ); //~ ERROR this function takes
-  three_diff(          1.0          ); //~ ERROR this function takes
-  three_diff(   1                   ); //~ ERROR this function takes
+  three_diff(          1.0,     ""  ); //~ ERROR function takes
+  three_diff(   1,              ""  ); //~ ERROR function takes
+  three_diff(   1,     1.0          ); //~ ERROR function takes
+  three_diff(                   ""  ); //~ ERROR function takes
+  three_diff(          1.0          ); //~ ERROR function takes
+  three_diff(   1                   ); //~ ERROR function takes
 
   /*              i32     f32     f32     &str   */
-  four_repeated(                               ); //~ ERROR this function takes
-  four_repeated(   1,                     ""   ); //~ ERROR this function takes
+  four_repeated(                               ); //~ ERROR function takes
+  four_repeated(   1,                     ""   ); //~ ERROR function takes
 
   /*        i32   f32   i32   f32   &str   */
-  complex(                               ); //~ ERROR this function takes
-  complex(   1,                     ""   ); //~ ERROR this function takes
+  complex(                               ); //~ ERROR function takes
+  complex(   1,                     ""   ); //~ ERROR function takes
 }
index 73678482b30256dc05b51228f80e4f47b7b08105..86e94a4382c0d31b89da6341c5b40e582e118d36 100644 (file)
@@ -7,11 +7,11 @@ fn three_args(_a: i32, _b: f32, _c: &str) {}
 
 fn main() {
   // Extra + Invalid
-  two_args(1, "", X {}); //~ ERROR this function takes
-  three_args(1, "", X {}, ""); //~ ERROR this function takes
+  two_args(1, "", X {}); //~ ERROR function takes
+  three_args(1, "", X {}, ""); //~ ERROR function takes
 
   // Missing and Invalid
-  three_args(1, X {}); //~ ERROR this function takes
+  three_args(1, X {}); //~ ERROR function takes
 
   // Missing and Extra
   three_args(1, "", X {}); //~ ERROR arguments to this function are incorrect
@@ -20,5 +20,5 @@ fn main() {
   three_args("", X {}, 1); //~ ERROR arguments to this function are incorrect
 
   // Swapped and missing
-  three_args("", 1); //~ ERROR this function takes
+  three_args("", 1); //~ ERROR function takes
 }
index bd430194c5edf6ec57b7f41fa34d243bf3ff4ca2..4928943294bf54ae81a2a3c3988c051904a3fda5 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     qux.foo(a, b, c, d, e, f, g, h, i, j, k, l);
    |         ---                ^ expected `i32`, found `&i32`
    |         |
-   |         arguments to this function are incorrect
+   |         arguments to this method are incorrect
    |
 note: associated function defined here
   --> $DIR/too-long.rs:4:8
index bad0268772b79185be9595194533667595ec8449..5b040d3e4d31db2839ff0ec87580506e2e73e30c 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/slice-mut-2.rs:7:18
    |
-LL |     let x: &[isize] = &[1, 2, 3, 4, 5];
-   |                       ---------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4, 5]`
-...
 LL |     let _ = &mut x[2..4];
    |                  ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let x: &[isize] = &mut [1, 2, 3, 4, 5];
+   |                       ~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 2df17f2e03620aad6daa5a02043989ab39d531d4..f6c50c2e1fdd08e3131e435f76b603d00a1840dc 100644 (file)
@@ -30,12 +30,7 @@ error: asm outputs are not allowed with the `noreturn` option
 LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
    |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
 ...
-LL |       m!(in out lateout inout inlateout const sym
-   |  _____-
-   | |_____|
-   | |_____|
-   | |_____|
-   | |
+LL | /     m!(in out lateout inout inlateout const sym
 LL | |        pure nomem readonly preserves_flags
 LL | |        noreturn nostack options);
    | |                                -
index 0ce1f1d8f7f4ad33ac6926ed5e09576b03027e54..89f2b3bb7d0fe2e9fef3c90d3ec1fe91d205029e 100644 (file)
@@ -25,12 +25,10 @@ fn main() {
 
         // Outputs require mutable places
 
-        let v: Vec<u64> = vec![0, 1, 2];
+        let v: Vec<u64> = vec![0, 1, 2]; //~ ERROR cannot borrow `v` as mutable
         asm!("{}", in(reg) v[0]);
         asm!("{}", out(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
         asm!("{}", inout(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
 
         // Sym operands must point to a function or static
     }
index eef16a165a87556f187cbdbca517682024a1b87a..41f7c01dc82b1f1878d277ced92289e156d4d6a8 100644 (file)
@@ -25,24 +25,22 @@ LL |         let mut y: u64 = 0;
    |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-2-2.rs:30:29
+  --> $DIR/type-check-2-2.rs:28:13
    |
 LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
+   |             ^ not mutable
 LL |         asm!("{}", in(reg) v[0]);
 LL |         asm!("{}", out(reg) v[0]);
-   |                             ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-2-2.rs:32:31
-   |
-LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
-...
+   |                             - cannot borrow as mutable
 LL |         asm!("{}", inout(reg) v[0]);
-   |                               ^ cannot borrow as mutable
+   |                               - cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Vec<u64> = vec![0, 1, 2];
+   |             +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0381, E0596.
 For more information about an error, try `rustc --explain E0381`.
index 6ac2ac5a77914e0df1a59c495d76d26e27597cd1..80a8c8c77cfec1c0cdaa13bcaa24e33e310e9210 100644 (file)
@@ -30,12 +30,7 @@ error: asm outputs are not allowed with the `noreturn` option
 LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
    |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
 ...
-LL |       m!(in out lateout inout inlateout const sym
-   |  _____-
-   | |_____|
-   | |_____|
-   | |_____|
-   | |
+LL | /     m!(in out lateout inout inlateout const sym
 LL | |        pure nomem readonly preserves_flags
 LL | |        noreturn nostack att_syntax options);
    | |                                           -
index 8198df91095f94acd111902c194f58d3cea735f4..1d579ccc90eec1eaaf9eb58209dc79f247c99c80 100644 (file)
@@ -22,11 +22,10 @@ fn main() {
         // Outputs require mutable places
 
         let v: Vec<u64> = vec![0, 1, 2];
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
         asm!("{}", in(reg) v[0]);
         asm!("{}", out(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
         asm!("{}", inout(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
 
         // Sym operands must point to a function or static
 
index bd90461e52c17d750ea85c353e8c0384ae788a88..7970e76d6a1f4e74ae49531248cb057d79af9cae 100644 (file)
@@ -25,24 +25,22 @@ LL |         let mut y: u64 = 0;
    |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-5.rs:26:29
+  --> $DIR/type-check-5.rs:24:13
    |
 LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
-LL |         asm!("{}", in(reg) v[0]);
-LL |         asm!("{}", out(reg) v[0]);
-   |                             ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-5.rs:28:31
-   |
-LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
+   |             ^ not mutable
 ...
+LL |         asm!("{}", out(reg) v[0]);
+   |                             - cannot borrow as mutable
 LL |         asm!("{}", inout(reg) v[0]);
-   |                               ^ cannot borrow as mutable
+   |                               - cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Vec<u64> = vec![0, 1, 2];
+   |             +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0381, E0596.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/associated-consts/issue-105330.rs b/src/test/ui/associated-consts/issue-105330.rs
new file mode 100644 (file)
index 0000000..86e45f1
--- /dev/null
@@ -0,0 +1,21 @@
+pub trait TraitWAssocConst {
+    const A:   usize;
+}
+pub struct Demo {}
+
+impl TraitWAssocConst for impl Demo { //~ ERROR E0404
+    //~^ ERROR E0562
+    pubconst A: str = 32; //~ ERROR expected one of
+}
+
+fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
+    foo::<Demo>()(); //~ ERROR E0271
+    //~^ ERROR E0618
+    //~| ERROR E0277
+}
+
+fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
+    //~^ ERROR E0658
+    foo::<Demo>(); //~ ERROR E0277
+    //~^ ERROR E0271
+}
diff --git a/src/test/ui/associated-consts/issue-105330.stderr b/src/test/ui/associated-consts/issue-105330.stderr
new file mode 100644 (file)
index 0000000..30c3801
--- /dev/null
@@ -0,0 +1,113 @@
+error: expected one of `!` or `::`, found `A`
+  --> $DIR/issue-105330.rs:8:14
+   |
+LL | impl TraitWAssocConst for impl Demo {
+   |                                     - while parsing this item list starting here
+LL |
+LL |     pubconst A: str = 32;
+   |              ^ expected one of `!` or `::`
+LL | }
+   | - the item list ends here
+
+error[E0404]: expected trait, found struct `Demo`
+  --> $DIR/issue-105330.rs:6:32
+   |
+LL | impl TraitWAssocConst for impl Demo {
+   |                                ^^^^ not a trait
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-105330.rs:11:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |                            ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-105330.rs:17:29
+   |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+   |                             ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
+  --> $DIR/issue-105330.rs:6:27
+   |
+LL | impl TraitWAssocConst for impl Demo {
+   |                           ^^^^^^^^^
+
+error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
+  --> $DIR/issue-105330.rs:12:11
+   |
+LL |     foo::<Demo>()();
+   |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:11
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
+  --> $DIR/issue-105330.rs:12:11
+   |
+LL |     foo::<Demo>()();
+   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
+   |
+   = note: expected constant `32`
+              found constant `<Demo as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |                            ^^^^ required by this bound in `foo`
+
+error[E0618]: expected function, found `()`
+  --> $DIR/issue-105330.rs:12:5
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   | ----------------------------------- `foo::<Demo>` defined here returns `()`
+LL |     foo::<Demo>()();
+   |     ^^^^^^^^^^^^^--
+   |     |
+   |     call expression requires function
+
+error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
+  --> $DIR/issue-105330.rs:19:11
+   |
+LL |     foo::<Demo>();
+   |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:11
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
+  --> $DIR/issue-105330.rs:19:11
+   |
+LL |     foo::<Demo>();
+   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
+   |
+   = note: expected constant `32`
+              found constant `<Demo as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |                            ^^^^ required by this bound in `foo`
+
+error[E0131]: `main` function is not allowed to have generic parameters
+  --> $DIR/issue-105330.rs:17:8
+   |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
+For more information about an error, try `rustc --explain E0131`.
index e761c6c62a6cf43c549b4da0d70b4cff84605167..d6b18d4ed32e7e907aa77455f73c3666030e5c6b 100644 (file)
@@ -32,7 +32,7 @@ error[E0308]: mismatched types
 LL | fn f() { ModelT.chip_paint(Blue); }
    |                 ---------- ^^^^ expected struct `Black`, found struct `Blue`
    |                 |
-   |                 arguments to this function are incorrect
+   |                 arguments to this method are incorrect
    |
 note: associated function defined here
   --> $DIR/associated-type-projection-from-supertrait.rs:12:8
@@ -46,7 +46,7 @@ error[E0308]: mismatched types
 LL | fn g() { ModelU.chip_paint(Black); }
    |                 ---------- ^^^^^ expected struct `Blue`, found struct `Black`
    |                 |
-   |                 arguments to this function are incorrect
+   |                 arguments to this method are incorrect
    |
 note: associated function defined here
   --> $DIR/associated-type-projection-from-supertrait.rs:12:8
index 389cc7beddd83a5ccfce4cc1dbd079ed970fd82b..6552c8be7808926e1b4acb7cd25536ed2c708795 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-for-unimpl-trait.rs:10:5
+  --> $DIR/associated-types-for-unimpl-trait.rs:10:40
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |                                        ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
index 1feaa612ee688714a363c578f9900edca268067f..b2ee1b5e6d04527fb56eb6eddb0b65ce4e8d8381 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-bound.rs:11:5
+  --> $DIR/associated-types-no-suitable-bound.rs:11:21
    |
 LL |     fn uhoh<T>(foo: <T as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
+   |                     ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
index cc3ed556115bc472b0b22e887e0ce8a040b051c1..2e40dbd065d3ef5579d5495b95590646d5e086a0 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
+  --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |                                        ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
index 18f2830d8b21504515f21599a3f13dc9e9328639..bd3ee2abd2c7604da8473500748cdb10eea74504 100644 (file)
@@ -1,14 +1,14 @@
 error[E0277]: the trait bound `(T, U): Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-supertrait.rs:22:5
+  --> $DIR/associated-types-no-suitable-supertrait.rs:22:40
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
 
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-supertrait.rs:17:5
+  --> $DIR/associated-types-no-suitable-supertrait.rs:17:40
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |                                        ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
index 66d59bccdbb68861f6c356e4b0c11569b5e09bb4..2e67c21940fc712c05aebfd3170128e287c54434 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
+  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40
    |
 LL |     fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |                                        ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
index 8df326351fa0cf48c82d755710bb9c91b7220448..7e21f7fc306d2b94ccde3ae44268bd7d2bc621fa 100644 (file)
@@ -22,8 +22,8 @@ note: type in trait
    |
 LL |     fn make() -> Self::Ty {
    |                  ^^^^^^^^
-   = note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
-              found fn pointer `fn() -> u8`
+   = note: expected signature `fn() -> <A<T> as Tr>::Ty`
+              found signature `fn() -> u8`
 
 error[E0053]: method `make` has an incompatible type for trait
   --> $DIR/defaults-specialization.rs:35:18
@@ -42,8 +42,8 @@ note: type in trait
    |
 LL |     fn make() -> Self::Ty {
    |                  ^^^^^^^^
-   = note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
-              found fn pointer `fn() -> bool`
+   = note: expected signature `fn() -> <B<T> as Tr>::Ty`
+              found signature `fn() -> bool`
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:10:9
diff --git a/src/test/ui/associated-types/issue-25700-1.rs b/src/test/ui/associated-types/issue-25700-1.rs
new file mode 100644 (file)
index 0000000..5e71a52
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+    fn clone(&self) -> Self { *self }
+}
+fn main() {
+    S::<()>(None);
+}
diff --git a/src/test/ui/associated-types/issue-25700-2.rs b/src/test/ui/associated-types/issue-25700-2.rs
new file mode 100644 (file)
index 0000000..89b1db4
--- /dev/null
@@ -0,0 +1,23 @@
+// run-pass
+pub trait Parser {
+    type Input;
+}
+
+pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
+
+#[allow(unused_tuple_struct_fields)]
+pub struct Map<P, F>(P, F);
+impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
+    type Input = u8;
+}
+
+trait AstId { type Untyped; }
+impl AstId for u32 { type Untyped = u32; }
+
+fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
+    Iter(Map(i, |_: Id::Untyped| {}), 42).1
+}
+
+pub fn main() {
+    assert_eq!(record_type::<u32>(3), 42);
+}
diff --git a/src/test/ui/associated-types/issue-25700.rs b/src/test/ui/associated-types/issue-25700.rs
new file mode 100644 (file)
index 0000000..e5b9a97
--- /dev/null
@@ -0,0 +1,14 @@
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+    fn clone(&self) -> Self { *self }
+}
+fn main() {
+    let t = S::<()>(None);
+    drop(t);
+    drop(t); //~ ERROR use of moved value
+}
diff --git a/src/test/ui/associated-types/issue-25700.stderr b/src/test/ui/associated-types/issue-25700.stderr
new file mode 100644 (file)
index 0000000..fa309a5
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0382]: use of moved value: `t`
+  --> $DIR/issue-25700.rs:13:10
+   |
+LL |     let t = S::<()>(None);
+   |         - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait
+LL |     drop(t);
+   |          - value moved here
+LL |     drop(t);
+   |          ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index 9e68e9e77515bc6633b0ad3e8a603f98c765d587..551f13ee178da679e098d86985dfc43ed7f28534 100644 (file)
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
 {
     fn get_service(
     //~^ ERROR the trait bound `Bug: Foo` is not satisfied
-    //~| ERROR the trait bound `Bug: Foo` is not satisfied
         &self,
     ) -> Self::AssocType;
+    //~^ ERROR the trait bound `Bug: Foo` is not satisfied
 }
 
 fn with_factory<H>(factory: dyn ThriftService<()>) {}
index 62cf1f37a77139e3ce71dab1e8587d329bcba70f..a84b599b52b68d2c28913dfdb70c5d08f8714bf6 100644 (file)
@@ -20,7 +20,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |     ) -> Self::AssocType;
+LL | |
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -34,7 +34,6 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
    |
 LL | /     fn get_service(
 LL | |
-LL | |
 LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -45,20 +44,16 @@ LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
 
 error[E0277]: the trait bound `(): Foo` is not satisfied
-  --> $DIR/issue-59324.rs:23:1
+  --> $DIR/issue-59324.rs:23:29
    |
 LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |                             ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
-  --> $DIR/issue-59324.rs:16:5
+  --> $DIR/issue-59324.rs:19:10
    |
-LL | /     fn get_service(
-LL | |
-LL | |
-LL | |         &self,
-LL | |     ) -> Self::AssocType;
-   | |_________________________^ the trait `Foo` is not implemented for `Bug`
+LL |     ) -> Self::AssocType;
+   |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
 help: consider further restricting this bound
    |
index 22d2928f2f5641801c4b858ccbe6217d4aa8d830..13e7222551aaf1f5783d93dcdd2b09973cb1d9fd 100644 (file)
@@ -9,8 +9,8 @@ note: type in trait
    |
 LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected fn pointer `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
-              found fn pointer `fn(&i32) -> impl Future<Output = i32>`
+   = note: expected signature `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
+              found signature `fn(&i32) -> impl Future<Output = i32>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issue-105501.rs b/src/test/ui/async-await/issue-105501.rs
new file mode 100644 (file)
index 0000000..f30d2a9
--- /dev/null
@@ -0,0 +1,165 @@
+// check-pass
+// edition:2018
+
+// This is a regression test for https://github.com/rust-lang/rust/issues/105501.
+// It was minified from the published `msf-ice:0.2.1` crate which failed in a crater run.
+// A faulty compiler was triggering a `higher-ranked lifetime error`:
+//
+// > could not prove `[async block@...]: Send`
+
+use mini_futures::Stream;
+
+fn is_send(_: impl Send) {}
+
+pub fn main() {
+    let fut = async {
+        let mut stream = mini_futures::iter([()])
+            .then(|_| async {})
+            .map(|_| async { None })
+            .buffered()
+            .filter_map(std::future::ready);
+
+        stream.next().await
+    };
+
+    is_send(async move {
+        let _: Option<()> = fut.await;
+    });
+}
+
+// this is a simplified subset of `futures::StreamExt` and related types
+mod mini_futures {
+    use std::future::Future;
+    use std::pin::Pin;
+    use std::task::{Context, Poll};
+
+    pub fn iter<I>(_: I) -> Iter<I::IntoIter>
+    where
+        I: IntoIterator,
+    {
+        todo!()
+    }
+
+    pub trait Stream {
+        type Item;
+
+        fn then<Fut, F>(self, _: F) -> Then<Self, Fut, F>
+        where
+            F: FnMut(Self::Item) -> Fut,
+            Fut: Future,
+            Self: Sized,
+        {
+            todo!()
+        }
+
+        fn map<T, F>(self, _: F) -> Map<Self, F>
+        where
+            F: FnMut(Self::Item) -> T,
+            Self: Sized,
+        {
+            todo!()
+        }
+
+        fn buffered(self) -> Buffered<Self>
+        where
+            Self::Item: Future,
+            Self: Sized,
+        {
+            todo!()
+        }
+
+        fn filter_map<Fut, T, F>(self, _: F) -> FilterMap<Self, Fut, F>
+        where
+            F: FnMut(Self::Item) -> Fut,
+            Fut: Future<Output = Option<T>>,
+            Self: Sized,
+        {
+            todo!()
+        }
+
+        fn next(&mut self) -> Next<'_, Self> {
+            todo!()
+        }
+    }
+
+    pub struct Iter<I> {
+        __: I,
+    }
+    impl<I> Stream for Iter<I>
+    where
+        I: Iterator,
+    {
+        type Item = I::Item;
+    }
+
+    pub struct Then<St, Fut, F> {
+        __: (St, Fut, F),
+    }
+    impl<St, Fut, F> Stream for Then<St, Fut, F>
+    where
+        St: Stream,
+        F: FnMut(St::Item) -> Fut,
+        Fut: Future,
+    {
+        type Item = Fut::Output;
+    }
+
+    pub struct Map<St, F> {
+        __: (St, F),
+    }
+    impl<St, F> Stream for Map<St, F>
+    where
+        St: Stream,
+        F: FnMut1<St::Item>,
+    {
+        type Item = F::Output;
+    }
+
+    pub trait FnMut1<A> {
+        type Output;
+    }
+    impl<T, A, R> FnMut1<A> for T
+    where
+        T: FnMut(A) -> R,
+    {
+        type Output = R;
+    }
+
+    pub struct Buffered<St>
+    where
+        St: Stream,
+        St::Item: Future,
+    {
+        __: (St, St::Item),
+    }
+    impl<St> Stream for Buffered<St>
+    where
+        St: Stream,
+        St::Item: Future,
+    {
+        type Item = <St::Item as Future>::Output;
+    }
+
+    pub struct FilterMap<St, Fut, F> {
+        __: (St, Fut, F),
+    }
+    impl<St, Fut, F, T> Stream for FilterMap<St, Fut, F>
+    where
+        St: Stream,
+        F: FnMut1<St::Item, Output = Fut>,
+        Fut: Future<Output = Option<T>>,
+    {
+        type Item = T;
+    }
+
+    pub struct Next<'a, St: ?Sized> {
+        __: &'a mut St,
+    }
+    impl<St: ?Sized + Stream> Future for Next<'_, St> {
+        type Output = Option<St::Item>;
+
+        fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+            todo!()
+        }
+    }
+}
index 2d3bb48e03be83ac3a5a042eaf9de06774d0c7c5..bf50443288032c74ada58b0664b71563b1cc570f 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/issue-61452.rs:4:5
    |
-LL | pub async fn f(x: Option<usize>) {
-   |                - help: consider changing this to be mutable: `mut x`
 LL |     x.take();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | pub async fn f(mut x: Option<usize>) {
+   |                +++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/issue-61452.rs:9:5
index 163053471b52daad9ce7b5394f0a693b323ba10e..e58f74546899ba16f109a820b887bc592e8154db 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
   --> $DIR/issue-61187.rs:6:5
    |
-LL | async fn response(data: Vec<u8>) {
-   |                   ---- help: consider changing this to be mutable: `mut data`
 LL |     data.reverse();
    |     ^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | async fn response(mut data: Vec<u8>) {
+   |                   +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/attributes/z-crate-attr.rs b/src/test/ui/attributes/z-crate-attr.rs
new file mode 100644 (file)
index 0000000..1021774
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+// This test checks if an unstable feature is enabled with the -Zcrate-attr=feature(foo) flag. If
+// the exact feature used here is causing problems feel free to replace it with another
+// perma-unstable feature.
+
+// compile-flags: -Zcrate-attr=feature(abi_unadjusted)
+
+#![allow(dead_code)]
+
+extern "unadjusted" fn foo() {}
+
+fn main() {}
index 1b4ac6edcb0d5547ce40b2099cb97c3bb501c55e..20c7fb3a98395bddc9bf07788364b7630dd9d867 100644 (file)
@@ -19,7 +19,7 @@ fn main() {
 
     let y = Int(2);
     //~^ HELP consider changing this to be mutable
-    //~| SUGGESTION mut y
+    //~| SUGGESTION mut
     y   //~ ERROR cannot borrow `y` as mutable, as it is not declared as mutable
         //~| cannot borrow as mutable
     +=
index ce555da8975a7af622eb377ec85f114da441d0b6..2910c910d55241bf4c660f667df359b0ac38289f 100644 (file)
@@ -10,11 +10,13 @@ LL |     x;
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/augmented-assignments.rs:23:5
    |
-LL |     let y = Int(2);
-   |         - help: consider changing this to be mutable: `mut y`
-...
 LL |     y
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut y = Int(2);
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 5963dab9f4aab255fa97c9f4f5a5cd22182a526f..4cc1d821d0a06e6e245041ddbc8f49ae80f9d950 100644 (file)
@@ -1,20 +1,24 @@
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrow-raw-address-of-deref-mutability.rs:8:13
    |
-LL |     let x = &0;
-   |             -- help: consider changing this to be a mutable reference: `&mut 0`
-LL |
 LL |     let q = &raw mut *x;
    |             ^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let x = &mut 0;
+   |             ~~~~~~
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
   --> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13
    |
-LL |     let x = &0 as *const i32;
-   |             -- help: consider changing this to be a mutable pointer: `&mut 0`
-LL |
 LL |     let q = &raw mut *x;
    |             ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL |     let x = &mut 0 as *const i32;
+   |             ~~~~~~
 
 error: aborting due to 2 previous errors
 
index 869375cb2c61be2a0911f28e05e42e2c409b3cd2..a7748209187121bdd6f779b8d9e5644f0eaa0582 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:5:13
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     let y = &raw mut x;
    |             ^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:11:17
@@ -18,13 +21,16 @@ LL |         let y = &raw mut x;
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:21:5
    |
-LL |     let f = || {
-   |         - help: consider changing this to be mutable: `mut f`
 LL |         let y = &raw mut x;
    |                          - calling `f` requires mutable binding due to mutable borrow of `x`
 LL |     };
 LL |     f();
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = || {
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-raw-address-of-mutability.rs:29:17
index e3a35c38a7c0373aaa52d10d666e35c072c671ea..26f3e2bbdb775901eaaed75553e50ca2b2c9c38e 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-access-permissions.rs:9:19
    |
-LL |     let x = 1;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |         let _y1 = &mut x;
    |                   ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 1;
+   |         +++
 
 error[E0596]: cannot borrow immutable static item `static_x` as mutable
   --> $DIR/borrowck-access-permissions.rs:14:19
@@ -16,37 +18,46 @@ LL |         let _y1 = &mut static_x;
 error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable
   --> $DIR/borrowck-access-permissions.rs:22:19
    |
-LL |         let box_x = Box::new(1);
-   |             ----- help: consider changing this to be mutable: `mut box_x`
-...
 LL |         let _y1 = &mut *box_x;
    |                   ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut box_x = Box::new(1);
+   |             +++
 
 error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-access-permissions.rs:30:19
    |
-LL |         let ref_x = &x;
-   |                     -- help: consider changing this to be a mutable reference: `&mut x`
-...
 LL |         let _y1 = &mut *ref_x;
    |                   ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |         let ref_x = &mut x;
+   |                     ~~~~~~
 
 error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer
   --> $DIR/borrowck-access-permissions.rs:39:23
    |
-LL |         let ptr_x : *const _ = &x;
-   |                                -- help: consider changing this to be a mutable pointer: `&mut x`
-...
 LL |             let _y1 = &mut *ptr_x;
    |                       ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL |         let ptr_x : *const _ = &mut x;
+   |                                ~~~~~~
 
 error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-access-permissions.rs:48:18
    |
-LL |         let foo_ref = &foo;
-   |                       ---- help: consider changing this to be a mutable reference: `&mut foo`
 LL |         let _y = &mut *foo_ref.f;
    |                  ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |         let foo_ref = &mut foo;
+   |                       ~~~~~~~~
 
 error: aborting due to 6 previous errors
 
index d4d646e390c31f5269ff87c814641679bb3cdbd6..1c992dfccebfbd95b775536183f5c766c93021a0 100644 (file)
@@ -1,34 +1,46 @@
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:10:5
    |
-LL | fn func(arg: S) {
-   |         --- help: consider changing this to be mutable: `mut arg`
 LL |     arg.mutate();
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn func(mut arg: S) {
+   |         +++
 
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:15:9
    |
-LL |     fn method(&self, arg: S) {
-   |                      --- help: consider changing this to be mutable: `mut arg`
 LL |         arg.mutate();
    |         ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn method(&self, mut arg: S) {
+   |                      +++
 
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:21:9
    |
-LL |     fn default(&self, arg: S) {
-   |                       --- help: consider changing this to be mutable: `mut arg`
 LL |         arg.mutate();
    |         ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn default(&self, mut arg: S) {
+   |                       +++
 
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:32:17
    |
 LL |     (|arg: S| { arg.mutate() })(s);
-   |       ---       ^^^^^^^^^^^^ cannot borrow as mutable
-   |       |
-   |       help: consider changing this to be mutable: `mut arg`
+   |                 ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     (|mut arg: S| { arg.mutate() })(s);
+   |       +++
 
 error: aborting due to 4 previous errors
 
index 0475df447445df05067ce82fab23feb4ebe0b11e..cbacc87a0e85845e7cbce3efccbe71c093dd02dd 100644 (file)
@@ -1,18 +1,24 @@
 error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference
   --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:9:5
    |
-LL | fn a(s: &S) {
-   |         -- help: consider changing this to be a mutable reference: `&mut S<'_>`
 LL |     *s.pointer += 1;
    |     ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn a(s: &mut S<'_>) {
+   |         ~~~~~~~~~~
 
 error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference
   --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5
    |
-LL | fn c(s: & &mut S) {
-   |         -------- help: consider changing this to be a mutable reference: `&mut &mut S<'_>`
 LL |     *s.pointer += 1;
    |     ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn c(s: &mut &mut S<'_>) {
+   |         ~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
index 186ecddd6d61df3ff01e052cd5349897980860c9..19ef0301a2d76b3b5b8d560caf6d0ccce2d276d5 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5
    |
-LL |     let x = Foo { x: 3 };
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     x.printme();
    |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = Foo { x: 3 };
+   |         +++
 
 error: aborting due to previous error
 
index e00d69f89d36eefea364e61d44bf7c330b1469b8..c2351aacdae62a35706b5e52a5e194f82816ed19 100644 (file)
@@ -105,10 +105,13 @@ LL |     *bar1;
 error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
   --> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16
    |
-LL |     let foo = make_foo();
-   |         --- help: consider changing this to be mutable: `mut foo`
 LL |     let bar1 = &mut foo.bar1;
    |                ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = make_foo();
+   |         +++
 
 error: aborting due to 11 previous errors
 
index ce5ce56dea27fe85e2962e2f4173a08c485662ac..8fcaaa883b22c6520869d9a7e757a64ac28578ca 100644 (file)
@@ -105,10 +105,13 @@ LL |     *bar1;
 error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
   --> $DIR/borrowck-borrow-from-stack-variable.rs:120:16
    |
-LL |     let foo = make_foo();
-   |         --- help: consider changing this to be mutable: `mut foo`
 LL |     let bar1 = &mut foo.bar1;
    |                ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = make_foo();
+   |         +++
 
 error: aborting due to 11 previous errors
 
index 237071e16fc669b0f0e27414cc5ba5ccce10e115..3c28ff56e4196158358496cfc3f7953744f97e28 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
   --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
    |
-LL |     let a: Box<_> = Box::new(A);
-   |         - help: consider changing this to be mutable: `mut a`
 LL |     a.foo();
    |     ^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut a: Box<_> = Box::new(A);
+   |         +++
 
 error: aborting due to previous error
 
index c99c0f77982edecf4a03edc402f7f8afb3526755..ce9f7aa050a0aca647a80a16cfc7471afa4784f4 100644 (file)
@@ -20,10 +20,13 @@ LL |     **t1 = 22;
 error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:26
    |
-LL | fn foo4(t0: & &mut isize) {
-   |             ------------ help: consider changing this to be a mutable reference: `&mut &mut isize`
 LL |     let x:  &mut isize = &mut **t0;
    |                          ^^^^^^^^^ `t0` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn foo4(t0: &mut &mut isize) {
+   |             ~~~~~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
index 4995029a70f7e2696abf82883acf3c2369d4cdf8..0f320af2657603bf20d82a7ab4f7e300974633ae 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn foo(_:String) {}
 
 fn main()
@@ -8,4 +10,11 @@ fn main()
         Some(_) => {}
         None => { foo(my_str); } //~ ERROR [E0382]
     }
+
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if let Some(()) = { drop(my_str); None } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR [E0382]
+    }
 }
index eaf4bb38bc5905532ba39d0081673df2cd6e3107..9fa28efd8554daeeb8344a7a91d0d25b03d88978 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `my_str`
-  --> $DIR/borrowck-drop-from-guard.rs:9:23
+  --> $DIR/borrowck-drop-from-guard.rs:11:23
    |
 LL |     let my_str = "hello".to_owned();
    |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,23 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(my_str.clone()); false } => {}
    |                                 ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `my_str`
+  --> $DIR/borrowck-drop-from-guard.rs:18:23
+   |
+LL |     let my_str = "hello".to_owned();
+   |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL |     match Some(42) {
+LL |         Some(_) if let Some(()) = { drop(my_str); None } => {}
+   |                                          ------ value moved here
+LL |         Some(_) => {}
+LL |         None => { foo(my_str); }
+   |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+   |                                                ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index 4c0e46d453142eeb838bd463b2a857e981ae559f..42a55b7a854ba407b8670ea37dde36b86c61302f 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `***p`, which is behind a `&` reference
   --> $DIR/borrowck-issue-14498.rs:16:5
    |
-LL |     let p = &y;
-   |             -- help: consider changing this to be a mutable reference: `&mut y`
 LL |     ***p = 2;
    |     ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let p = &mut y;
+   |             ~~~~~~
 
 error[E0506]: cannot assign to `**y` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:25:5
index ecf5382e863e00336d9ec449722a272f8044d628..87135f0bb438fee1a9997c45c7c3179b0a8a8c68 100644 (file)
@@ -9,6 +9,10 @@ LL |     let _x = Rc::new(vec![1, 2]).into_iter();
    |
 note: `into_iter` takes ownership of the receiver `self`, which moves value
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |     let _x = Rc::new(vec![1, 2]).clone().into_iter();
+   |                                  ++++++++
 
 error: aborting due to previous error
 
index d58548f22049a683748c72511b0c967e3c39db60..20528e3f0ee089d6fb949b186a0d66b15a1f6002 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25
    |
-LL |     let x: isize = 3;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     let y: &mut isize = &mut x;
    |                         ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: isize = 3;
+   |         +++
 
 error: aborting due to previous error
 
index 8e7ffdc6819a5c679ced357abdb9db3b76d7a76e..8ab472e64c7a929093691ef97102d71092900d89 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11
    |
-LL |     let v = vec![1, 2, 3];
-   |         - help: consider changing this to be mutable: `mut v`
 LL |     write(&mut v);
    |           ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut v = vec![1, 2, 3];
+   |         +++
 
 error: aborting due to previous error
 
index 9cbceeb945ccc631f4f6fca7c8afa5d9ca5de926..d80a9e81576f49227034b0a895b192e823691067 100644 (file)
@@ -1,9 +1,11 @@
+#![feature(if_let_guard)]
+
 enum Enum<'a> {
     A(&'a isize),
     B(bool),
 }
 
-fn foo() -> isize {
+fn if_guard() -> isize {
     let mut n = 42;
     let mut x = Enum::A(&mut n);
     match x {
@@ -16,6 +18,17 @@ fn foo() -> isize {
     }
 }
 
-fn main() {
-    foo();
+fn if_let_guard() -> isize {
+    let mut n = 42;
+    let mut x = Enum::A(&mut n);
+    match x {
+        Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+        //~^ ERROR cannot assign `x` in match guard
+        Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+        //~^ ERROR cannot mutably borrow `x` in match guard
+        Enum::A(p) => *p,
+        Enum::B(_) => 2,
+    }
 }
+
+fn main() {}
index 6d05e97252d928df4fdb633518281dbc61331833..dbb3272fdc351242b4de455ec9d086c38ea6ac33 100644 (file)
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:10:25
+  --> $DIR/borrowck-mutate-in-guard.rs:12:25
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -7,7 +7,7 @@ LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
    |                         ^^^^^^^^^^^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:12:33
+  --> $DIR/borrowck-mutate-in-guard.rs:14:33
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -15,6 +15,23 @@ LL |     match x {
 LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
    |                                 ^^^^^^ cannot mutably borrow
 
-error: aborting due to 2 previous errors
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:25:40
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+   |                                        ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:27:48
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+   |                                                ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0510`.
index ddb63b5ec0fbec2d0a8a39e291fb0f8d0ab7b91f..723b19f4124ac10b6877486bd215d201fa6107bf 100644 (file)
@@ -11,11 +11,13 @@ LL |     use_mut(sp);
 error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-overloaded-call.rs:67:5
    |
-LL |     let s = SFnMut {
-   |         - help: consider changing this to be mutable: `mut s`
-...
 LL |     s(3);
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut s = SFnMut {
+   |         +++
 
 error[E0382]: use of moved value: `s`
   --> $DIR/borrowck-overloaded-call.rs:75:5
index 284cab296084292a147df652f889fc277b145a31..d9590e446c756b73ca4042777f310563728bc9b2 100644 (file)
@@ -105,10 +105,13 @@ LL |     use_imm(_bar1);
 error[E0596]: cannot borrow `foo.bar1` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-reborrow-from-mut.rs:88:17
    |
-LL | fn borrow_mut_from_imm(foo: &Foo) {
-   |                             ---- help: consider changing this to be a mutable reference: `&mut Foo`
 LL |     let _bar1 = &mut foo.bar1;
    |                 ^^^^^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn borrow_mut_from_imm(foo: &mut Foo) {
+   |                             ~~~~~~~~
 
 error: aborting due to 11 previous errors
 
index e744fc6b54b1a4fccb6f4e48f7a052948ab283b9..5cfd81bd00428e1644e215476b8e76656a204398 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
   --> $DIR/borrowck-ref-mut-of-imm.rs:4:12
    |
-LL | fn destructure(x: Option<isize>) -> isize {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |       Some(ref mut v) => *v
    |            ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn destructure(mut x: Option<isize>) -> isize {
+   |                +++
 
 error: aborting due to previous error
 
index d46ef126da481a9c0ecc8606efd727d2349db5f8..3634676463c62f516be4f82a4da52570b14778b4 100644 (file)
@@ -11,10 +11,13 @@ LL |     use_mut(g);
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-unboxed-closures.rs:7:5
    |
-LL | fn b<F:FnMut(isize, isize) -> isize>(f: F) {
-   |                                      - help: consider changing this to be mutable: `mut f`
 LL |     f(1, 2);
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn b<F:FnMut(isize, isize) -> isize>(mut f: F) {
+   |                                      +++
 
 error[E0382]: use of moved value: `f`
   --> $DIR/borrowck-unboxed-closures.rs:12:5
index 7238dd14433ce888cfba8b7b303acd6cec186471..d5392e7d66fa4cbbe8e27adef49c5799599c4a2f 100644 (file)
@@ -1,18 +1,24 @@
 error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable
   --> $DIR/immut-function-arguments.rs:2:5
    |
-LL | fn f(y: Box<isize>) {
-   |      - help: consider changing this to be mutable: `mut y`
 LL |     *y = 5;
    |     ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn f(mut y: Box<isize>) {
+   |      +++
 
 error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable
   --> $DIR/immut-function-arguments.rs:6:35
    |
 LL |     let _frob = |q: Box<isize>| { *q = 2; };
-   |                  -                ^^^^^^ cannot assign
-   |                  |
-   |                  help: consider changing this to be mutable: `mut q`
+   |                                   ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let _frob = |mut q: Box<isize>| { *q = 2; };
+   |                  +++
 
 error: aborting due to 2 previous errors
 
index 07125b98a1f7d10ad744d63da681b0cdd2738a9a..5b824adc6e2737647f4f739fb87ac8e8088baa93 100644 (file)
@@ -1,8 +1,15 @@
+#![feature(if_let_guard)]
+
 fn main() {
     let a = Some("...".to_owned());
     let b = match a {
         Some(_) if { drop(a); false } => None,
         x => x, //~ ERROR use of moved value: `a`
     };
-    println!("{:?}", b);
+
+    let a = Some("...".to_owned());
+    let b = match a {
+        Some(_) if let Some(()) = { drop(a); None } => None,
+        x => x, //~ ERROR use of moved value: `a`
+    };
 }
index ad898fcabd9dbfab6df5fb1b94e7b02585f10aad..18f371c20735a909dbbcbfa2a85baae1ba33b533 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `a`
-  --> $DIR/issue-31287-drop-in-guard.rs:5:9
+  --> $DIR/issue-31287-drop-in-guard.rs:7:9
    |
 LL |     let a = Some("...".to_owned());
    |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
@@ -14,6 +14,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(a.clone()); false } => None,
    |                            ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `a`
+  --> $DIR/issue-31287-drop-in-guard.rs:13:9
+   |
+LL |     let a = Some("...".to_owned());
+   |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL |     let b = match a {
+LL |         Some(_) if let Some(()) = { drop(a); None } => None,
+   |                                          - value moved here
+LL |         x => x,
+   |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+   |                                           ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index b7623a54056d809321115d790a204aa8c2aac4ba..774b6cf0ea6d23277ba9824bfe379c00d32b5f72 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
    |
-LL |         let t: Tuple = (S(0), 0);
-   |             - help: consider changing this to be mutable: `mut t`
-LL |         drop(t);
 LL |         t.0 = S(1);
    |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             +++
 
 error[E0382]: assign to part of moved value: `t`
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
@@ -20,20 +22,24 @@ LL |         t.0 = S(1);
 error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9
    |
-LL |         let t: Tuple = (S(0), 0);
-   |             - help: consider changing this to be mutable: `mut t`
-...
 LL |         t.1 = 2;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             +++
 
 error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
    |
-LL |         let u: Tpair = Tpair(S(0), 0);
-   |             - help: consider changing this to be mutable: `mut u`
-LL |         drop(u);
 LL |         u.0 = S(1);
    |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             +++
 
 error[E0382]: assign to part of moved value: `u`
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
@@ -48,20 +54,24 @@ LL |         u.0 = S(1);
 error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
    |
-LL |         let u: Tpair = Tpair(S(0), 0);
-   |             - help: consider changing this to be mutable: `mut u`
-...
 LL |         u.1 = 2;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             +++
 
 error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
    |
-LL |         let v: Spair = Spair { x: S(0), y: 0 };
-   |             - help: consider changing this to be mutable: `mut v`
-LL |         drop(v);
 LL |         v.x = S(1);
    |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             +++
 
 error[E0382]: assign to part of moved value: `v`
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
@@ -76,11 +86,13 @@ LL |         v.x = S(1);
 error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
    |
-LL |         let v: Spair = Spair { x: S(0), y: 0 };
-   |             - help: consider changing this to be mutable: `mut v`
-...
 LL |         v.y = 2;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             +++
 
 error: aborting due to 9 previous errors
 
index 13033962142fa51583cd5065639db7221824a981..7da7dba68ab7aaf537a8a24ff100797e264f3f5c 100644 (file)
@@ -10,11 +10,13 @@ LL |     rofl.push(Vec::new());
 error[E0594]: cannot assign to `*r`, which is behind a `&` reference
   --> $DIR/issue-85765.rs:12:5
    |
-LL |     let r = &mutvar;
-   |             ------- help: consider changing this to be a mutable reference: `&mut mutvar`
-LL |
 LL |     *r = 0;
    |     ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let r = &mut mutvar;
+   |             ~~~~~~~~~~~
 
 error[E0594]: cannot assign to `*x`, which is behind a `&` reference
   --> $DIR/issue-85765.rs:19:5
diff --git a/src/test/ui/borrowck/issue-93078.rs b/src/test/ui/borrowck/issue-93078.rs
new file mode 100644 (file)
index 0000000..2e608c5
--- /dev/null
@@ -0,0 +1,15 @@
+trait Modify {
+    fn modify(&mut self) ;
+}
+
+impl<T> Modify for T  {
+    fn modify(&mut self)  {}
+}
+
+trait Foo {
+    fn mute(&mut self) {
+        self.modify(); //~ ERROR cannot borrow `self` as mutable
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/issue-93078.stderr b/src/test/ui/borrowck/issue-93078.stderr
new file mode 100644 (file)
index 0000000..771a652
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
+  --> $DIR/issue-93078.rs:11:9
+   |
+LL |         self.modify();
+   |         ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = note: as `Self` may be unsized, this call attempts to take `&mut &mut self`
+   = note: however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
index 031128af47655e34fa8cef6f8552eb2f887afabe..afa76594f0b5e71de8641ee857acda79a6dcd633 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `self.foo`, which is behind a `&` reference
   --> $DIR/issue-93093.rs:8:9
    |
-LL |     async fn bar(&self) {
-   |                  ----- help: consider changing this to be a mutable reference: `&mut self`
-LL |
 LL |         self.foo += 1;
    |         ^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     async fn bar(&mut self) {
+   |                  ~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/many-mutable-borrows.rs b/src/test/ui/borrowck/many-mutable-borrows.rs
new file mode 100644 (file)
index 0000000..3e6ea9d
--- /dev/null
@@ -0,0 +1,18 @@
+fn main() {
+    let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+}
diff --git a/src/test/ui/borrowck/many-mutable-borrows.stderr b/src/test/ui/borrowck/many-mutable-borrows.stderr
new file mode 100644 (file)
index 0000000..aa0cbcf
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/many-mutable-borrows.rs:2:9
+   |
+LL |     let v = Vec::new();
+   |         ^ not mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+   |
+   = note: ...and 5 other attempted mutable borrows
+help: consider changing this to be mutable
+   |
+LL |     let mut v = Vec::new();
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
index 7cdb16b282d540253dd756071d02611639dc3ef5..477a2aa48d5dcb42e3eab13b0ab0f5562327dab9 100644 (file)
@@ -2,15 +2,14 @@
 #![crate_type = "rlib"]
 
 pub fn f(b: &mut i32) {
-    //~^ NOTE the binding is already a mutable borrow
+    //~^ ERROR cannot borrow
+    //~| NOTE not mutable
     //~| NOTE the binding is already a mutable borrow
     h(&mut b);
-    //~^ ERROR cannot borrow
-    //~| NOTE cannot borrow as mutable
+    //~^ NOTE cannot borrow as mutable
     //~| HELP try removing `&mut` here
     g(&mut &mut b);
-    //~^ ERROR cannot borrow
-    //~| NOTE cannot borrow as mutable
+    //~^ NOTE cannot borrow as mutable
     //~| HELP try removing `&mut` here
 }
 
index 7782047574ce8e7b6b8ba9b6180c280fdf66d8bc..c6f75b1c0d022f5b7fb83d38a382a7fb4e3efc7a 100644 (file)
@@ -1,8 +1,14 @@
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:7:7
+  --> $DIR/mut-borrow-of-mut-ref.rs:4:10
    |
+LL | pub fn f(b: &mut i32) {
+   |          ^ not mutable
+...
 LL |     h(&mut b);
-   |       ^^^^^^ cannot borrow as mutable
+   |       ------ cannot borrow as mutable
+...
+LL |     g(&mut &mut b);
+   |            ------ cannot borrow as mutable
    |
 note: the binding is already a mutable borrow
   --> $DIR/mut-borrow-of-mut-ref.rs:4:13
@@ -14,18 +20,6 @@ help: try removing `&mut` here
 LL -     h(&mut b);
 LL +     h(b);
    |
-
-error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:11:12
-   |
-LL |     g(&mut &mut b);
-   |            ^^^^^^ cannot borrow as mutable
-   |
-note: the binding is already a mutable borrow
-  --> $DIR/mut-borrow-of-mut-ref.rs:4:13
-   |
-LL | pub fn f(b: &mut i32) {
-   |             ^^^^^^^^
 help: try removing `&mut` here
    |
 LL -     g(&mut &mut b);
@@ -33,13 +27,13 @@ LL +     g(&mut b);
    |
 
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:18:12
+  --> $DIR/mut-borrow-of-mut-ref.rs:17:12
    |
 LL |     h(&mut &mut b);
    |            ^^^^^^ cannot borrow as mutable
    |
 note: the binding is already a mutable borrow
-  --> $DIR/mut-borrow-of-mut-ref.rs:17:13
+  --> $DIR/mut-borrow-of-mut-ref.rs:16:13
    |
 LL | pub fn g(b: &mut i32) {
    |             ^^^^^^^^
@@ -50,7 +44,7 @@ LL +     h(&mut b);
    |
 
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:35:5
+  --> $DIR/mut-borrow-of-mut-ref.rs:34:5
    |
 LL |     f.bar();
    |     ^^^^^^^ cannot borrow as mutable
@@ -60,6 +54,6 @@ help: consider making the binding mutable
 LL | pub fn baz(mut f: &mut String) {
    |            +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
index 5be0df1376135b91c11276ff0836b04878894188..82116425f06ca478b24ae570c54fd6287b8402bb 100644 (file)
@@ -50,9 +50,9 @@ fn ref_closure(mut x: (i32,)) {
     });
 }
 
-fn imm_local(x: (i32,)) {
-    &mut x; //~ ERROR
-    &mut x.0; //~ ERROR
+fn imm_local(x: (i32,)) { //~ ERROR
+    &mut x;
+    &mut x.0;
 }
 
 fn imm_capture(x: (i32,)) {
index dd29ae492d604fa758dfc593df29f24f0f969942..d7c602718f1736ccf54fa451f4d2aff9e8d0f1e3 100644 (file)
@@ -1,37 +1,46 @@
 error[E0594]: cannot assign to `*x`, which is behind a `&` reference
   --> $DIR/mutability-errors.rs:9:5
    |
-LL | fn named_ref(x: &(i32,)) {
-   |                 ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
 LL |     *x = (1,);
    |     ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
 
 error[E0594]: cannot assign to `x.0`, which is behind a `&` reference
   --> $DIR/mutability-errors.rs:10:5
    |
-LL | fn named_ref(x: &(i32,)) {
-   |                 ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
-LL |     *x = (1,);
 LL |     x.0 = 1;
    |     ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/mutability-errors.rs:11:5
    |
-LL | fn named_ref(x: &(i32,)) {
-   |                 ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
-...
 LL |     &mut *x;
    |     ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
 
 error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference
   --> $DIR/mutability-errors.rs:12:5
    |
-LL | fn named_ref(x: &(i32,)) {
-   |                 ------- help: consider changing this to be a mutable reference: `&mut (i32,)`
-...
 LL |     &mut x.0;
    |     ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn named_ref(x: &mut (i32,)) {
+   |                 ~~~~~~~~~~~
 
 error[E0594]: cannot assign to data in a `&` reference
   --> $DIR/mutability-errors.rs:16:5
@@ -60,37 +69,46 @@ LL |     &mut f().0;
 error[E0594]: cannot assign to `*x`, which is behind a `*const` pointer
   --> $DIR/mutability-errors.rs:23:5
    |
-LL | unsafe fn named_ptr(x: *const (i32,)) {
-   |                        ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
 LL |     *x = (1,);
    |     ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
 
 error[E0594]: cannot assign to `x.0`, which is behind a `*const` pointer
   --> $DIR/mutability-errors.rs:24:5
    |
-LL | unsafe fn named_ptr(x: *const (i32,)) {
-   |                        ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
-LL |     *x = (1,);
 LL |     (*x).0 = 1;
    |     ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
   --> $DIR/mutability-errors.rs:25:5
    |
-LL | unsafe fn named_ptr(x: *const (i32,)) {
-   |                        ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
-...
 LL |     &mut *x;
    |     ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
 
 error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer
   --> $DIR/mutability-errors.rs:26:5
    |
-LL | unsafe fn named_ptr(x: *const (i32,)) {
-   |                        ------------- help: consider changing this to be a mutable pointer: `*mut (i32,)`
-...
 LL |     &mut (*x).0;
    |     ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable pointer
+   |
+LL | unsafe fn named_ptr(x: *mut (i32,)) {
+   |                        ~~~~~~~~~~~
 
 error[E0594]: cannot assign to data in a `*const` pointer
   --> $DIR/mutability-errors.rs:30:5
@@ -227,21 +245,19 @@ LL |         &mut x.0;
    |         ^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
-  --> $DIR/mutability-errors.rs:54:5
+  --> $DIR/mutability-errors.rs:53:14
    |
 LL | fn imm_local(x: (i32,)) {
-   |              - help: consider changing this to be mutable: `mut x`
-LL |     &mut x;
-   |     ^^^^^^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
-  --> $DIR/mutability-errors.rs:55:5
-   |
-LL | fn imm_local(x: (i32,)) {
-   |              - help: consider changing this to be mutable: `mut x`
+   |              ^ not mutable
 LL |     &mut x;
+   |     ------ cannot borrow as mutable
 LL |     &mut x.0;
-   |     ^^^^^^^^ cannot borrow as mutable
+   |     -------- cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_local(mut x: (i32,)) {
+   |              +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:60:9
@@ -339,7 +355,7 @@ error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item
 LL |     &mut X.0;
    |     ^^^^^^^^ cannot borrow as mutable
 
-error: aborting due to 38 previous errors
+error: aborting due to 37 previous errors
 
 Some errors have detailed explanations: E0594, E0596.
 For more information about an error, try `rustc --explain E0594`.
index a3885b5f5caea4593bcaf8df52d32a95cf7dd63d..81e5bc45d4d38bbadc11c530131be0f0888ec90b 100644 (file)
@@ -11,11 +11,13 @@ LL |     x.a = 1;
 error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
   --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5
    |
-LL |     let x: Foo;
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x.a = 1;
 LL |     x.b = 22;
    |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: Foo;
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 49c81adad49373c788f0e80ad693b131490c3954..ba0457809ad43b591c49f2227ea852dcf2344e6a 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
   --> $DIR/reassignment_immutable_fields_twice.rs:7:5
    |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x = (22, 44);
 LL |     x.0 = 1;
    |     ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: (u32, u32);
+   |         +++
 
 error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/reassignment_immutable_fields_twice.rs:12:5
index 1e3b071ef92927781fd4db9524547ab77016648e..930fea9158d45405ebbbe7d7ca3162d850d8ca29 100644 (file)
@@ -22,8 +22,8 @@ error[E0308]: method not compatible with trait
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
-              found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+   = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+              found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
 note: the lifetime `'c` as defined here...
   --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
    |
@@ -41,8 +41,8 @@ error[E0308]: method not compatible with trait
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
-              found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+   = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+              found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
 note: the lifetime `'c` as defined here...
   --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
    |
diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed
new file mode 100644 (file)
index 0000000..b0c5376
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+// Test that a by-ref `FnMut` closure gets an error when it tries to
+// consume a value.
+
+fn call<F>(f: F) where F : Fn() {
+    f();
+}
+
+fn main() {
+    let y = vec![format!("World")];
+    call(|| {
+        y.clone().into_iter();
+        //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
+    });
+}
index d54b09c5da95ac95f8ed2d2c5e0ab32bf122ecef..4666b8a3373531f1f4794a9165970d895d204186 100644 (file)
@@ -1,3 +1,4 @@
+// run-rustfix
 // Test that a by-ref `FnMut` closure gets an error when it tries to
 // consume a value.
 
index b1367c652188bd8f4bafd95c2addf26ea843e94b..f033d53bf8e482a99eff20d9af2dcd2bc07c2ade 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure
-  --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9
+  --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:12:9
    |
 LL |     let y = vec![format!("World")];
    |         - captured outer variable
@@ -12,6 +12,10 @@ LL |         y.into_iter();
    |
 note: `into_iter` takes ownership of the receiver `self`, which moves `y`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |         y.clone().into_iter();
+   |           ++++++++
 
 error: aborting due to previous error
 
index 24407a71ce6997184531b3c1018f6bf474efbbf1..acd8a25dc533bd6120419dc82c5483e92f6243ff 100644 (file)
@@ -19,8 +19,8 @@ extern "C" fn bar(f: isize, x: u8) {}
 
 fn main() {
     unsafe {
-        foo(); //~ ERROR this function takes at least 2 arguments but 0 arguments were supplied
-        foo(1); //~ ERROR this function takes at least 2 arguments but 1 argument was supplied
+        foo(); //~ ERROR function takes at least 2 arguments but 0 arguments were supplied
+        foo(1); //~ ERROR function takes at least 2 arguments but 1 argument was supplied
 
         let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~ ERROR mismatched types
         let y: extern "C" fn(f: isize, x: u8, ...) = bar; //~ ERROR mismatched types
index a20acce4c76b2e64e986ddff4dbc8c93ad1bb5be..6c78a71b0fc9d9faa06f7ea43f5391491341bba8 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 fn main() {
     1 + 2;
index f4ebf91924ced1384025f84367366d7af67e70ce..834c8935e762006e4b04b60a5b1c3cf1ca99de4c 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 fn main() {
     assert_eq!(1, 1);
index dbd60fc8bb1ff1d9bb5b7d146c57f8f445d102c0..4a7cd9396690a9d2d7015760905e91ef63bd2356 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo {}
 
index ae5224dbd6fa86c96ab78097517a321dd3663714..ed0f5dc9bd371208beef2cc965aad75399b412d2 100644 (file)
@@ -1,6 +1,6 @@
 // check-fail
 // known-bug: unknown
-// compile-flags: -Z chalk --edition=2021
+// compile-flags: -Z trait-solver=chalk --edition=2021
 
 fn main() -> () {}
 
index 7712e9465424b46534009e5f6248b1acf893bbd5..a478c006ef1ca05de08f59389836b038fc977f8c 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 // Test that `Clone` is correctly implemented for builtin types.
 
index df25bad622b3d09e83d3d6090f176f5cf914e887..21de72b6fcccbc8c2d3eca1a2a1d30eca121564c 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index 568e2e30c418ca7c91ca3b714c1f42717c0712f4..a908a1e97ecd9c3491a7ddcd70ef3a2b73cff2c8 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 fn main() -> () {
     let t = || {};
index d70c6f8055ddf92adfd332a3d1963888ed08ce93..7d33e12d8be1739e31dd876e504dada3e66007ca 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index 66f57c2d11009fe1a2d4ea82520b5968b88a326e..c8dfd4c3a5b4fa51d6b1d8e1e4551b8c6ba31613 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo: Sized { }
 
index 758a7185e3912aac602c4363de7c6ee4b72c6363..325044ad6349a94a32b50f74186c401372703c58 100644 (file)
@@ -1,6 +1,6 @@
 // Split out of impl_wf.rs to work around rust aborting compilation early
 
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo: Sized { }
 
index a2730219fbe2ac0d1a7b70d386ee758961846aa0..f0f24d485cd8748993f9391d5f5538489c11181c 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index 774c46e401ca30260f86e73dc4f27f26f9f573a9..3eda7102decd111771c6de6bdd17c5ec143b3868 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index e3c7569592149d236215c06570469ddf1e120f6e..c8762001e6a1d948d77ac1b8ee618ca26a6f21e3 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 #![allow(dead_code)]
 
index b5432ce0e307bb9e2bf5c024a4dda0f0906aff28..7d4f81f12eaf5be4a033e20d789ff13223864897 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 #![allow(dead_code)]
 
index 673f08d78abd0ee08102294a9ed6634b04ac4e46..5b70c4abbb551c3e741f558e042a3d537105aee8 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 #![allow(dead_code)]
 
index f586cf083915debc7986e0d2e59d5a69f4149cac..6f79b3ba386a52c533dff6eceaf3bf8f6308cb8a 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index 94a0716d383546c2f307cac7232cd2f3a1543fd1..6be0d4dd5bd2978c07a2240d914f834af585c322 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 struct Foo<'a, T> where Box<T>: Clone {
     _x: std::marker::PhantomData<&'a T>,
index d8f6180ceb315ab07a41346ca0d9904f9a131478..8f5b358220bf73233f36096f59c111191e43bcb4 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Bar { }
 
index a48979491a10de7144a331e911d39a55923ff2d0..f04a1deea87536356df2e3df7a52528884209ef1 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo<F: ?Sized> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
 {
index 19cff8db7cb4ad59c792a43f2ed000a8986d5bda..a21d2f31963c79ec88a83de6b173a47463ee2522 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 use std::borrow::Borrow;
 
index 0f0df29019e7bbc1dbea32322013e0b696abb71e..edddc382152344de1a2eeea2c96db9aed0f8597c 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 fn main() {
     println!("hello");
index d6a8dd7a4a20317ddadfd00f2659683b1cd8bbae..19bb2ae1497230af55976f8991c6f0f0cb9c9fa5 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index 87324a5f79bdd760da0e9c63e6b822764bbcb874..c2c8aa6aabec2990a6901e37db124fd05adf349f 100644 (file)
@@ -1,6 +1,6 @@
 // FIXME(chalk): should fail, see comments
 // check-fail
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 #![feature(trivial_bounds)]
 
@@ -25,6 +25,6 @@ fn foo<T: Foo>() {
 fn main() {
     // For some reason, the error is duplicated...
 
-    foo::<S>() //~ ERROR the type `S` is not well-formed (chalk)
-    //~^ ERROR the type `S` is not well-formed (chalk)
+    foo::<S>() //~ ERROR the type `S` is not well-formed
+    //~^ ERROR the type `S` is not well-formed
 }
index fddd58959278efb72c4129873cf78306a4e9f911..cead5adeaaadb36826c91ebc838c00892dbd8405 100644 (file)
@@ -1,10 +1,10 @@
-error: the type `S` is not well-formed (chalk)
+error: the type `S` is not well-formed
   --> $DIR/recursive_where_clause_on_type.rs:28:11
    |
 LL |     foo::<S>()
    |           ^
 
-error: the type `S` is not well-formed (chalk)
+error: the type `S` is not well-formed
   --> $DIR/recursive_where_clause_on_type.rs:28:5
    |
 LL |     foo::<S>()
index eeff9fd9b80a36098d7f90944fab6d08f56ab092..540ae51e57f6d80c2a7819da256f460ca8cd0672 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 trait Bar: Foo { }
index d56abc42bf540c048951ac55830e97e3c50bf309..144d9788b82e6c558b69f355adedb6d2e2d1eb36 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 use std::fmt::Display;
 
index 8a2e1cf599008acd80bcb98765711110013d3642..f97dbf6b7e7748649213c7b7144fcce67495c8e8 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 trait Bar<U> where U: Foo { }
index 8673f5319bdf05c55bf580eb1fb33967590b1ed6..70f1b4265e4990507b5a935ea8690f1965358e62 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Eq { }
 trait Hash: Eq { }
index 369777a7904af85e2e74fbfdc3363fe113003173..d7167d0dc57fa3da2a18fbeb8dac9bcbe7970d58 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 impl Foo for i32 { }
index eeeefcfb7dd15cd846411f5dd6c8307174cd42ae..37d2f5ca832ce6c9f0f7cbe69ecd0f16842e2f4f 100644 (file)
@@ -1,5 +1,5 @@
 // check-fail
-// compile-flags: -Z chalk
+// compile-flags: -Z trait-solver=chalk
 
 trait Foo { }
 
index 29ececea5d3941ea4f61099ef1deb17155bcc425..69d799783a94bfaea471bb9a3f6466ad133d3fa1 100644 (file)
@@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")]
    |                   |
    |                   help: did you mean: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
index bdd6cb79b60b09f414508c21884102b06cace66d..00f50c33e1ccdb6b64ffb17488756027661ea5d1 100644 (file)
@@ -8,10 +8,9 @@ struct Point {
 fn main() {
     let mut c = {
         let mut p = Point {x: "1".to_string(), y: "2".to_string() };
-        || {
+        || { //~ ERROR closure may outlive the current block, but it borrows `p`
            let x = &mut p.x;
            println!("{:?}", p);
-            //~^ ERROR `p` does not live long enough
         }
     };
     c();
index dab1809a381ee28a1e5241253069faadc37d8126..ee923804786852c807d88782b9caa5126d5ba775 100644 (file)
@@ -1,18 +1,22 @@
-error[E0597]: `p` does not live long enough
-  --> $DIR/borrowck-3.rs:13:29
+error[E0373]: closure may outlive the current block, but it borrows `p`, which is owned by the current block
+  --> $DIR/borrowck-3.rs:11:9
    |
-LL |     let mut c = {
-   |         ----- borrow later stored here
-LL |         let mut p = Point {x: "1".to_string(), y: "2".to_string() };
 LL |         || {
-   |         -- value captured here
+   |         ^^ may outlive borrowed value `p`
 LL |            let x = &mut p.x;
 LL |            println!("{:?}", p);
-   |                             ^ borrowed value does not live long enough
-...
-LL |     };
-   |     - `p` dropped here while still borrowed
+   |                             - `p` is borrowed here
+   |
+note: block requires argument type to outlive `'1`
+  --> $DIR/borrowck-3.rs:9:9
+   |
+LL |     let mut c = {
+   |         ^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+   |
+LL |         move || {
+   |         ++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
index 481d7e58529eebe089afd91fe0460ba870b05600..95f36fc042c4fd8668725c98a2cc28a1560f4efb 100644 (file)
@@ -1,14 +1,16 @@
 error[E0596]: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference
   --> $DIR/mut_ref.rs:12:13
    |
-LL |     let ref_mref_x = &mref_x;
-   |                      ------- help: consider changing this to be a mutable reference: `&mut mref_x`
-LL |
 LL |     let c = || {
    |             ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
 LL |
 LL |         **ref_mref_x = y;
    |         ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let ref_mref_x = &mut mref_x;
+   |                      ~~~~~~~~~~~
 
 error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
   --> $DIR/mut_ref.rs:26:13
index bf9e1febdbba40a55ba062b64b82a824dd8bde40..239f071ca92b3152f60c86e011ce4b22fc74106f 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
    |
-LL |     let callback = || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         &mut my_var;
    |              ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = || {
+   |         +++
 
 error: aborting due to previous error
 
index b67cec6a609f0857eaa8e6a63e0839aa7ba29941..1ec279f03eff5ff24369ea55dd03769424d0b889 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
    |
-LL |     let callback = move || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         &mut my_var;
    |              ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = move || {
+   |         +++
 
 error: aborting due to previous error
 
index 6e98549f6b84f8cbf1c0252e8c14cb6e5b77bdf1..22a62ce735053f2596b6ea0860e0b8f2a56792ae 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutation-in-closure.rs:6:5
    |
-LL |     let callback = || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         my_var = true;
    |         ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = || {
+   |         +++
 
 error: aborting due to previous error
 
index edd55422a0bd490350d671b9b1b82bcaa31e6614..a2222f8cc9570bd21d1afa21cdcee4f15e926af6 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
    |
-LL |     let callback = move || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         my_var = true;
    |         ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = move || {
+   |         +++
 
 error: aborting due to previous error
 
index 3f564afff58e2df73a1424e327fc0bc8551c7ed2..03b18c3f70c63ae59dfb5b938b2dbcf69d1fed8b 100644 (file)
@@ -2,11 +2,14 @@ error[E0596]: cannot borrow `bar` as mutable, as it is not declared as mutable
   --> $DIR/issue-81700-mut-borrow.rs:3:5
    |
 LL |     let bar = || { foo(x); };
-   |         ---            - calling `bar` requires mutable binding due to mutable borrow of `x`
-   |         |
-   |         help: consider changing this to be mutable: `mut bar`
+   |                        - calling `bar` requires mutable binding due to mutable borrow of `x`
 LL |     bar();
    |     ^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut bar = || { foo(x); };
+   |         +++
 
 error: aborting due to previous error
 
index 802284b265821121fcb6fc5fa6bd7b2dbaf811d7..f0951b7d10873e73ec31645f30ba598707bdacdf 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
   --> $DIR/issue-82438-mut-without-upvar.rs:27:27
    |
-LL |     let c = |a, b, c, d| {};
-   |         - help: consider changing this to be mutable: `mut c`
-LL |
 LL |     A.f(participant_name, &mut c);
    |                           ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut c = |a, b, c, d| {};
+   |         +++
 
 error: aborting due to previous error
 
index c0bfad263f1785723fcf547ab3d1923a51904a90..5335a056cd89f16042846c102149823fdd159453 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/issue-84044-drop-non-mut.rs:5:10
    |
-LL |     let f = || {};
-   |         - help: consider changing this to be mutable: `mut f`
 LL |     drop(&mut f);
    |          ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = || {};
+   |         +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/supertrait-hint-cycle-2.rs b/src/test/ui/closures/supertrait-hint-cycle-2.rs
new file mode 100644 (file)
index 0000000..fda81b1
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+
+trait Foo<'a> {
+    type Input;
+}
+
+impl<F: Fn(u32)> Foo<'_> for F {
+    type Input = u32;
+}
+
+trait SuperFn: for<'a> Foo<'a> + for<'a> Fn(<Self as Foo<'a>>::Input) {}
+impl<T> SuperFn for T where T: for<'a> Fn(<Self as Foo<'a>>::Input) + for<'a> Foo<'a> {}
+
+fn needs_super(_: impl SuperFn) {}
+
+fn main() {
+    needs_super(|_: u32| {});
+}
diff --git a/src/test/ui/closures/supertrait-hint-cycle-3.rs b/src/test/ui/closures/supertrait-hint-cycle-3.rs
new file mode 100644 (file)
index 0000000..8149474
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+
+trait Foo<'a> {
+    type Input;
+}
+
+impl<F: Fn(u32)> Foo<'_> for F {
+    type Input = u32;
+}
+
+fn needs_super<F: for<'a> Fn(<F as Foo<'a>>::Input) + for<'a> Foo<'a>>(_: F) {}
+
+fn main() {
+    needs_super(|_: u32| {});
+}
diff --git a/src/test/ui/closures/supertrait-hint-cycle.rs b/src/test/ui/closures/supertrait-hint-cycle.rs
new file mode 100644 (file)
index 0000000..dbb06b2
--- /dev/null
@@ -0,0 +1,65 @@
+// edition:2021
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![feature(closure_lifetime_binder)]
+
+use std::future::Future;
+
+trait AsyncFn<I, R>: FnMut(I) -> Self::Fut {
+    type Fut: Future<Output = R>;
+}
+
+impl<F, I, R, Fut> AsyncFn<I, R> for F
+where
+    Fut: Future<Output = R>,
+    F: FnMut(I) -> Fut,
+{
+    type Fut = Fut;
+}
+
+async fn call<C, R, F>(mut ctx: C, mut f: F) -> Result<R, ()>
+where
+    F: for<'a> AsyncFn<&'a mut C, Result<R, ()>>,
+{
+    loop {
+        match f(&mut ctx).await {
+            Ok(val) => return Ok(val),
+            Err(_) => continue,
+        }
+    }
+}
+
+trait Cap<'a> {}
+impl<T> Cap<'_> for T {}
+
+fn works(ctx: &mut usize) {
+    let mut inner = 0;
+
+    type Ret<'a, 'b: 'a> = impl Future<Output = Result<usize, ()>> + 'a + Cap<'b>;
+
+    let callback = for<'a, 'b> |c: &'a mut &'b mut usize| -> Ret<'a, 'b> {
+        inner += 1;
+        async move {
+            let _c = c;
+            Ok(1usize)
+        }
+    };
+    call(ctx, callback);
+}
+
+fn doesnt_work_but_should(ctx: &mut usize) {
+    let mut inner = 0;
+
+    type Ret<'a, 'b: 'a> = impl Future<Output = Result<usize, ()>> + 'a + Cap<'b>;
+
+    call(ctx, for<'a, 'b> |c: &'a mut &'b mut usize| -> Ret<'a, 'b> {
+        inner += 1;
+        async move {
+            let _c = c;
+            Ok(1usize)
+        }
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/codegen/issue-82859-slice-miscompile.rs b/src/test/ui/codegen/issue-82859-slice-miscompile.rs
new file mode 100644 (file)
index 0000000..b64eb49
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+// compile-flags: -Copt-level=0 -Cdebuginfo=2
+
+// Make sure LLVM does not miscompile this.
+
+fn indirect_get_slice() -> &'static [usize] {
+    &[]
+}
+
+#[inline(always)]
+fn get_slice() -> &'static [usize] {
+    let ret = indirect_get_slice();
+    ret
+}
+
+fn main() {
+    let output = get_slice().len();
+    assert_eq!(output, 0);
+}
index a60f1c77a586317ce2f1681444daef840cb6e94d..9f8ce3b6183f2c7f2f37e77c9308a6789085d8ff 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/huge_multispan_highlight.rs:90:13
    |
-LL |     let x = "foo";
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     let y = &mut x;
    |             ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = "foo";
+   |         +++
 
 error: aborting due to previous error
 
index e0e369124a4be83557473cfd87160a5837647408..17bea2f366fa02bef3e48b32f6844ab712f77be9 100644 (file)
@@ -12,10 +12,10 @@ LL |         println!("{:?}", some_vec);
 note: `into_iter` takes ownership of the receiver `self`, which moves `some_vec`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
 LL |     some_vec.clone().into_iter();
-   |             ++++++++
+   |              ++++++++
 
 error: aborting due to previous error
 
index 6320187827256a9224b66e2b2b2454d8ad4b1534..7be5b92a7def0fa8e25d6b3fdf4124da77a8b9b7 100644 (file)
@@ -2,7 +2,7 @@ error[E0199]: implementing the trait `MySafeTrait` is not unsafe
   --> $DIR/coherence-default-trait-impl.rs:8:1
    |
 LL | unsafe impl MySafeTrait for Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `unsafe` from this trait implementation
    |
@@ -14,7 +14,7 @@ error[E0200]: the trait `MyUnsafeTrait` requires an `unsafe impl` declaration
   --> $DIR/coherence-default-trait-impl.rs:13:1
    |
 LL | impl MyUnsafeTrait for Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the trait `MyUnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
 help: add `unsafe` to this trait implementation
diff --git a/src/test/ui/command/command-argv0-debug.rs b/src/test/ui/command/command-argv0-debug.rs
deleted file mode 100644 (file)
index 4aba122..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// run-pass
-
-// ignore-windows - this is a unix-specific test
-// ignore-emscripten no processes
-// ignore-sgx no processes
-use std::os::unix::process::CommandExt;
-use std::process::Command;
-
-fn main() {
-    let mut command = Command::new("some-boring-name");
-
-    assert_eq!(format!("{:?}", command), r#""some-boring-name""#);
-
-    command.args(&["1", "2", "3"]);
-
-    assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#);
-
-    command.arg0("exciting-name");
-
-    assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#);
-}
diff --git a/src/test/ui/command/issue-10626.rs b/src/test/ui/command/issue-10626.rs
new file mode 100644 (file)
index 0000000..696a2dd
--- /dev/null
@@ -0,0 +1,26 @@
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+// Make sure that if a process doesn't have its stdio/stderr descriptors set up
+// that we don't die in a large ball of fire
+
+use std::env;
+use std::process::{Command, Stdio};
+
+pub fn main () {
+    let args: Vec<String> = env::args().collect();
+    if args.len() > 1 && args[1] == "child" {
+        for _ in 0..1000 {
+            println!("hello?");
+        }
+        for _ in 0..1000 {
+            println!("hello?");
+        }
+        return;
+    }
+
+    let mut p = Command::new(&args[0]);
+    p.arg("child").stdout(Stdio::null()).stderr(Stdio::null());
+    println!("{:?}", p.spawn().unwrap().wait());
+}
index 90e907157a50e782e2022d471590b6770ab43bac..cad942e646e3ee24037c579c69ae1f54950f6bae 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn poll(self, _: &mut Context<'_>) -> Poll<()> {
    |             expected struct `Pin`, found struct `MyFuture`
    |             help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
    |
-   = note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
-              found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
+   = note: expected signature `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
+              found signature `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
 
 error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/bad-self-type.rs:22:18
@@ -24,8 +24,8 @@ note: type in trait
    |
 LL |     fn foo(self);
    |            ^^^^
-   = note: expected fn pointer `fn(MyFuture)`
-              found fn pointer `fn(Box<MyFuture>)`
+   = note: expected signature `fn(MyFuture)`
+              found signature `fn(Box<MyFuture>)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/bad-self-type.rs:24:18
@@ -38,8 +38,8 @@ note: type in trait
    |
 LL |     fn bar(self) -> Option<()>;
    |                     ^^^^^^^^^^
-   = note: expected fn pointer `fn(MyFuture) -> Option<()>`
-              found fn pointer `fn(MyFuture)`
+   = note: expected signature `fn(MyFuture) -> Option<()>`
+              found signature `fn(MyFuture)`
 help: change the output type to match the trait
    |
 LL |     fn bar(self) -> Option<()> {}
index ee63f34b799a510ae3cd7e67804fa7579d4abc5e..52e23d03b148bfe5b60ca8030f155633bec6a6ed 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn from(_: fn((), (), &mut ())) -> Self {
    |                types differ in mutability
    |                help: change the parameter type to match the trait: `for<'a> fn((), (), &'a ())`
    |
-   = note: expected fn pointer `fn(for<'a> fn((), (), &'a ())) -> A`
-              found fn pointer `fn(for<'a> fn((), (), &'a mut ())) -> A`
+   = note: expected signature `fn(for<'a> fn((), (), &'a ())) -> A`
+              found signature `fn(for<'a> fn((), (), &'a mut ())) -> A`
 
 error[E0053]: method `from` has an incompatible type for trait
   --> $DIR/issue-90444.rs:11:16
@@ -19,8 +19,8 @@ LL |     fn from(_: fn((), (), u64)) -> Self {
    |                expected `u32`, found `u64`
    |                help: change the parameter type to match the trait: `fn((), (), u32)`
    |
-   = note: expected fn pointer `fn(fn((), (), u32)) -> B`
-              found fn pointer `fn(fn((), (), u64)) -> B`
+   = note: expected signature `fn(fn((), (), u32)) -> B`
+              found signature `fn(fn((), (), u64)) -> B`
 
 error: aborting due to 2 previous errors
 
index f01d7f4710c382d502ad33b9731b8c9147c4df9e..eb19d57ab05acfaa65ccec8d8ea43299482a388a 100644 (file)
@@ -6,6 +6,11 @@ LL |     fn renew<'b: 'a>(self) -> &'b mut [T];
 ...
 LL |     fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
    |                                                     ^^ impl has extra requirement `'a: 'b`
+   |
+help: copy the `where` clause predicates from the trait
+   |
+LL |     fn renew<'b: 'a>(self) -> &'b mut [T] where 'b: 'a {
+   |                                           ~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 4a3af65e9042bc350bdd31865af17e458f767356..1a471e18d9dc1f5291f11f7eddc5cf659728d6a2 100644 (file)
@@ -6,6 +6,12 @@ LL |     fn foo();
 ...
 LL |     fn foo() where 'a: 'b { }
    |                        ^^ impl has extra requirement `'a: 'b`
+   |
+help: remove the `where` clause
+   |
+LL -     fn foo() where 'a: 'b { }
+LL +     fn foo()  { }
+   |
 
 error: aborting due to previous error
 
index 49b5b1b92cd0523728ac2a7d1379afb80488c91e..1552d542d15dee44e9301862ef550af1b4288c49 100644 (file)
@@ -14,8 +14,8 @@ note: type in trait
    |
 LL |   fn b<C:Clone,D>(&self, x: C) -> C;
    |                             ^
-   = note: expected fn pointer `fn(&E, F) -> F`
-              found fn pointer `fn(&E, G) -> G`
+   = note: expected signature `fn(&E, F) -> F`
+              found signature `fn(&E, G) -> G`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
diff --git a/src/test/ui/const-generics/assoc_const_eq_diagnostic.rs b/src/test/ui/const-generics/assoc_const_eq_diagnostic.rs
new file mode 100644 (file)
index 0000000..4d0aaf8
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(associated_const_equality)]
+
+pub enum Mode {
+    Cool,
+}
+
+pub trait Parse {
+    const MODE: Mode;
+}
+
+pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
+//~^ ERROR expected associated constant bound
+//~| ERROR expected type
+
+fn no_help() -> Mode::Cool {}
+//~^ ERROR expected type, found variant
+
+fn main() {}
diff --git a/src/test/ui/const-generics/assoc_const_eq_diagnostic.stderr b/src/test/ui/const-generics/assoc_const_eq_diagnostic.stderr
new file mode 100644 (file)
index 0000000..ba727ee
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0573]: expected type, found variant `Mode::Cool`
+  --> $DIR/assoc_const_eq_diagnostic.rs:11:35
+   |
+LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
+   |                                   ^^^^^^^^^^
+   |                                   |
+   |                                   not a type
+   |                                   help: try using the variant's enum: `Mode`
+
+error[E0573]: expected type, found variant `Mode::Cool`
+  --> $DIR/assoc_const_eq_diagnostic.rs:15:17
+   |
+LL | fn no_help() -> Mode::Cool {}
+   |                 ^^^^^^^^^^
+   |                 |
+   |                 not a type
+   |                 help: try using the variant's enum: `Mode`
+
+error: expected associated constant bound, found type
+  --> $DIR/assoc_const_eq_diagnostic.rs:11:28
+   |
+LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
+   |                            ^^^^^^^^^^^^^^^^^ help: if equating a const, try wrapping with braces: `MODE = { const }`
+   |
+note: associated constant defined here
+  --> $DIR/assoc_const_eq_diagnostic.rs:8:5
+   |
+LL |     const MODE: Mode;
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/const-generics/ensure_is_evaluatable.rs b/src/test/ui/const-generics/ensure_is_evaluatable.rs
new file mode 100644 (file)
index 0000000..1e8d8c3
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize, const M: usize>() -> [(); N+2]
+where
+    [(); N + 1]:,
+    [(); M + 1]:,
+{
+    bar()
+    //~^ ERROR: unconstrained
+}
+
+fn bar<const N: usize>() -> [(); N]
+where
+    [(); N + 1]:,
+{
+    [(); N]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/ensure_is_evaluatable.stderr b/src/test/ui/const-generics/ensure_is_evaluatable.stderr
new file mode 100644 (file)
index 0000000..bf6c35a
--- /dev/null
@@ -0,0 +1,18 @@
+error: unconstrained generic constant
+  --> $DIR/ensure_is_evaluatable.rs:9:5
+   |
+LL |     bar()
+   |     ^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); N + 1]:`
+note: required by a bound in `bar`
+  --> $DIR/ensure_is_evaluatable.rs:15:10
+   |
+LL | fn bar<const N: usize>() -> [(); N]
+   |    --- required by a bound in this
+LL | where
+LL |     [(); N + 1]:,
+   |          ^^^^^ required by this bound in `bar`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/fn_with_two_const_inputs.rs b/src/test/ui/const-generics/fn_with_two_const_inputs.rs
new file mode 100644 (file)
index 0000000..0d6246a
--- /dev/null
@@ -0,0 +1,23 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+const fn both(_: usize, b: usize) -> usize {
+    b
+}
+
+fn foo<const N: usize, const M: usize>() -> [(); N + 2]
+where
+    [(); both(N + 1, M + 1)]:,
+{
+    bar()
+    //~^ ERROR: unconstrained generic constant
+}
+
+fn bar<const N: usize>() -> [(); N]
+where
+    [(); N + 1]:,
+{
+    [(); N]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/fn_with_two_const_inputs.stderr b/src/test/ui/const-generics/fn_with_two_const_inputs.stderr
new file mode 100644 (file)
index 0000000..614e7e0
--- /dev/null
@@ -0,0 +1,18 @@
+error: unconstrained generic constant
+  --> $DIR/fn_with_two_const_inputs.rs:12:5
+   |
+LL |     bar()
+   |     ^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); N + 1]:`
+note: required by a bound in `bar`
+  --> $DIR/fn_with_two_const_inputs.rs:18:10
+   |
+LL | fn bar<const N: usize>() -> [(); N]
+   |    --- required by a bound in this
+LL | where
+LL |     [(); N + 1]:,
+   |          ^^^^^ required by this bound in `bar`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/fn_with_two_same_const_inputs.rs b/src/test/ui/const-generics/fn_with_two_same_const_inputs.rs
new file mode 100644 (file)
index 0000000..f0ce093
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+const fn both(_: usize, b: usize) -> usize {
+    b
+}
+
+fn foo<const N: usize>()
+where
+    [(); both(N + 1, N + 1)]:,
+{
+    bar::<N>();
+}
+
+fn bar<const N: usize>()
+where
+    [(); N + 1]:,
+{
+}
+
+fn main() {}
index faa8b3d10de4f5996733aa4e5f90b7bf59b7ea55..10247ce6bcafd142dfc2dd66976b7842c4c53329 100644 (file)
@@ -13,5 +13,5 @@ fn test<T, const P: usize>() where Bool<{core::mem::size_of::<T>() > 4}>: True {
 
 fn main() {
     test::<2>();
-    //~^ ERROR this function takes 2 generic arguments
+    //~^ ERROR function takes 2 generic arguments
 }
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-99647.rs b/src/test/ui/const-generics/generic_const_exprs/issue-99647.rs
new file mode 100644 (file)
index 0000000..f797bed
--- /dev/null
@@ -0,0 +1,15 @@
+// edition:2018
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+#[allow(unused)]
+async fn foo<'a>() {
+    let _data = &mut [0u8; { 1 + 4 }];
+    bar().await
+}
+
+async fn bar() {}
+
+fn main() {}
index de2d126afd75a1bc9e057ff68cf465a207870fdf..8660cb2fb541d859188d1f0a080acbd925cad919 100644 (file)
@@ -4,8 +4,8 @@ fn foo<const X: usize, const Y: usize>() -> usize {
 
 fn main() {
     foo::<0>();
-    //~^ ERROR this function takes 2
+    //~^ ERROR function takes 2
 
     foo::<0, 0, 0>();
-    //~^ ERROR this function takes 2
+    //~^ ERROR function takes 2
 }
diff --git a/src/test/ui/const-generics/issues/issue-105037.rs b/src/test/ui/const-generics/issues/issue-105037.rs
new file mode 100644 (file)
index 0000000..f7d2394
--- /dev/null
@@ -0,0 +1,35 @@
+// run-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+trait Table<const D: usize>: Sync {
+    const COLUMNS: usize;
+}
+
+struct Table1<const D: usize>;
+impl<const D: usize> Table<D> for Table1<D> {
+    const COLUMNS: usize = 123;
+}
+
+struct Table2<const D: usize>;
+impl<const D: usize> Table<D> for Table2<D> {
+    const COLUMNS: usize = 456;
+}
+
+fn process_table<T: Table<D>, const D: usize>(_table: T)
+where
+    [(); T::COLUMNS]:,
+{
+}
+
+fn process_all_tables<const D: usize>()
+where
+    [(); Table2::<D>::COLUMNS]:,
+    [(); Table1::<D>::COLUMNS]:,
+{
+    process_table(Table1::<D>);
+    process_table(Table2::<D>);
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/two_matching_preds.rs b/src/test/ui/const-generics/two_matching_preds.rs
new file mode 100644 (file)
index 0000000..de608f7
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>()
+where
+    [(); N + 1]:,
+    [(); N + 1]:,
+{
+    bar::<N>();
+}
+
+fn bar<const N: usize>()
+where
+    [(); N + 1]:,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/unify_with_nested_expr.rs b/src/test/ui/const-generics/unify_with_nested_expr.rs
new file mode 100644 (file)
index 0000000..1271e09
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: usize>()
+where
+    [(); N + 1 + 1]:,
+{
+    bar();
+    //~^ ERROR: type annotations
+}
+
+fn bar<const N: usize>()
+where
+    [(); N + 1]:,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/unify_with_nested_expr.stderr b/src/test/ui/const-generics/unify_with_nested_expr.stderr
new file mode 100644 (file)
index 0000000..8bab0df
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0284]: type annotations needed
+  --> $DIR/unify_with_nested_expr.rs:8:5
+   |
+LL |     bar();
+   |     ^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
+   |
+note: required by a bound in `bar`
+  --> $DIR/unify_with_nested_expr.rs:14:10
+   |
+LL | fn bar<const N: usize>()
+   |    --- required by a bound in this
+LL | where
+LL |     [(); N + 1]:,
+   |          ^^^^^ required by this bound in `bar`
+help: consider specifying the generic argument
+   |
+LL |     bar::<N>();
+   |        +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr
deleted file mode 100644 (file)
index 0079bb3..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S0`
-  --> $DIR/forbidden_slices.rs:18:34
-   |
-LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `std::slice::from_raw_parts::<'_, ()>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S1`
-  --> $DIR/forbidden_slices.rs:19:33
-   |
-LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S2`
-  --> $DIR/forbidden_slices.rs:22:34
-   |
-LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:25:1
-   |
-LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:27:1
-   |
-LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:29:1
-   |
-LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:32:1
-   |
-LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID+0x2╼ 04 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |
-note: inside `std::slice::from_raw_parts::<'_, u64>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S8`
-  --> $DIR/forbidden_slices.rs:43:5
-   |
-LL |     from_raw_parts(ptr, 1)
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R0`
-  --> $DIR/forbidden_slices.rs:46:34
-   |
-LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, ()>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R1`
-  --> $DIR/forbidden_slices.rs:47:33
-   |
-LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::offset`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::add`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R2`
-  --> $DIR/forbidden_slices.rs:50:25
-   |
-LL |     from_ptr_range(ptr..ptr.add(2))
-   |                         ^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:52:1
-   |
-LL | pub static R4: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:57:1
-   |
-LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:62:1
-   |
-LL | pub static R6: &[bool] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: accessing memory with alignment 1, but alignment 2 is required
-   |
-note: inside `std::slice::from_raw_parts::<'_, u16>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `from_ptr_range::<'_, u16>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R7`
-  --> $DIR/forbidden_slices.rs:69:5
-   |
-LL |     from_ptr_range(ptr..ptr.add(4))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |
-note: inside `ptr::const_ptr::<impl *const u64>::offset`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u64>::add`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R8`
-  --> $DIR/forbidden_slices.rs:73:25
-   |
-LL |     from_ptr_range(ptr..ptr.add(1))
-   |                         ^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R9`
-  --> $DIR/forbidden_slices.rs:78:34
-   |
-LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R10`
-  --> $DIR/forbidden_slices.rs:79:35
-   |
-LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 18 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr
deleted file mode 100644 (file)
index f4f9fe6..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S0`
-  --> $DIR/forbidden_slices.rs:18:34
-   |
-LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `std::slice::from_raw_parts::<'_, ()>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S1`
-  --> $DIR/forbidden_slices.rs:19:33
-   |
-LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |
-note: inside `std::slice::from_raw_parts::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S2`
-  --> $DIR/forbidden_slices.rs:22:34
-   |
-LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:25:1
-   |
-LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:27:1
-   |
-LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:29:1
-   |
-LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:32:1
-   |
-LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |
-note: inside `std::slice::from_raw_parts::<'_, u64>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `S8`
-  --> $DIR/forbidden_slices.rs:43:5
-   |
-LL |     from_raw_parts(ptr, 1)
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R0`
-  --> $DIR/forbidden_slices.rs:46:34
-   |
-LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, ()>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R1`
-  --> $DIR/forbidden_slices.rs:47:33
-   |
-LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::offset`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::add`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R2`
-  --> $DIR/forbidden_slices.rs:50:25
-   |
-LL |     from_ptr_range(ptr..ptr.add(2))
-   |                         ^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:52:1
-   |
-LL | pub static R4: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:57:1
-   |
-LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:62:1
-   |
-LL | pub static R6: &[bool] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-   |
-   = note: accessing memory with alignment 1, but alignment 2 is required
-   |
-note: inside `std::slice::from_raw_parts::<'_, u16>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `from_ptr_range::<'_, u16>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R7`
-  --> $DIR/forbidden_slices.rs:69:5
-   |
-LL |     from_ptr_range(ptr..ptr.add(4))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |
-note: inside `ptr::const_ptr::<impl *const u64>::offset`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u64>::add`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `R8`
-  --> $DIR/forbidden_slices.rs:73:25
-   |
-LL |     from_ptr_range(ptr..ptr.add(1))
-   |                         ^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R9`
-  --> $DIR/forbidden_slices.rs:78:34
-   |
-LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
-   |
-note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R10`
-  --> $DIR/forbidden_slices.rs:79:35
-   |
-LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 18 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
index cc6100226dc1c00794ec90bbaf9524e9489f5f88..192b6a46de6073d0e84c41064b11e837cdf2700e 100644 (file)
@@ -1,5 +1,6 @@
-// stderr-per-bitwidth
-// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 // normalize-stderr-test "alloc\d+" -> "allocN"
 // error-pattern: could not evaluate static initializer
 #![feature(
@@ -78,7 +79,7 @@
 pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
 pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
 
-const D0: u32 = 0x11;
+const D0: u32 = 0x11111111; // Constant chosen for endianness-independent behavior.
 const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
 const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
 const D3: &u32 = &42;
diff --git a/src/test/ui/const-ptr/forbidden_slices.stderr b/src/test/ui/const-ptr/forbidden_slices.stderr
new file mode 100644 (file)
index 0000000..b423618
--- /dev/null
@@ -0,0 +1,240 @@
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+   = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S0`
+  --> $DIR/forbidden_slices.rs:19:34
+   |
+LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+   = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `std::slice::from_raw_parts::<'_, ()>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S1`
+  --> $DIR/forbidden_slices.rs:20:33
+   |
+LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+   = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S2`
+  --> $DIR/forbidden_slices.rs:23:34
+   |
+LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:26:1
+   |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:28:1
+   |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:30:1
+   |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:33:1
+   |
+LL | pub static S7: &[u16] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+   = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |
+note: inside `std::slice::from_raw_parts::<'_, u64>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `S8`
+  --> $DIR/forbidden_slices.rs:44:5
+   |
+LL |     from_raw_parts(ptr, 1)
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R0`
+  --> $DIR/forbidden_slices.rs:47:34
+   |
+LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, ()>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R1`
+  --> $DIR/forbidden_slices.rs:48:33
+   |
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const u32>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::add`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `R2`
+  --> $DIR/forbidden_slices.rs:51:25
+   |
+LL |     from_ptr_range(ptr..ptr.add(2))
+   |                         ^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:53:1
+   |
+LL | pub static R4: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:58:1
+   |
+LL | pub static R5: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:63:1
+   |
+LL | pub static R6: &[bool] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+   = note: accessing memory with alignment 1, but alignment 2 is required
+   |
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+  --> $DIR/forbidden_slices.rs:70:5
+   |
+LL |     from_ptr_range(ptr..ptr.add(4))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const u64>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u64>::add`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `R8`
+  --> $DIR/forbidden_slices.rs:74:25
+   |
+LL |     from_ptr_range(ptr..ptr.add(1))
+   |                         ^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
+   |
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R9`
+  --> $DIR/forbidden_slices.rs:79:34
+   |
+LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: could not evaluate static initializer
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
+   |
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R10`
+  --> $DIR/forbidden_slices.rs:80:35
+   |
+LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/raw-bytes.32bit.stderr b/src/test/ui/consts/const-eval/raw-bytes.32bit.stderr
new file mode 100644 (file)
index 0000000..91a4265
--- /dev/null
@@ -0,0 +1,596 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:20:1
+   |
+LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               01 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:28:1
+   |
+LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:42:1
+   |
+LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               01                                              │ .
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:44:1
+   |
+LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               03                                              │ .
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:50:1
+   |
+LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               78 00 00 00 ff ff ff ff                         │ x.......
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:54:1
+   |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:57:1
+   |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               00                                              │ .
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:59:1
+   |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:65:1
+   |
+LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               2a 00 00 00                                     │ *...
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:71:1
+   |
+LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               14 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:74:1
+   |
+LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               00 00 00 00 ╾ALLOC_ID╼                         │ ....╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:82:1
+   |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ╾ALLOC_ID╼                                     │ ╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:86:1
+   |
+LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ╾ALLOC_ID╼                                     │ ╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:90:1
+   |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:93:1
+   |
+LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:96:1
+   |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               39 05 00 00                                     │ 9...
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:99:1
+   |
+LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               39 05 00 00                                     │ 9...
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:102:1
+   |
+LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:104:1
+   |
+LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               0d 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:106:1
+   |
+LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ╾ALLOC_ID╼                                     │ ╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:112:1
+   |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               01 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:137:1
+   |
+LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:139:1
+   |
+LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:141:1
+   |
+LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:144:1
+   |
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:146:1
+   |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:148:1
+   |
+LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:152:1
+   |
+LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:154:1
+   |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ff ff ff 7f                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:157:1
+   |
+LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:160:1
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ╾ALLOC_ID╼                                     │ ╾──╼
+           }
+
+note: erroneous constant used
+  --> $DIR/raw-bytes.rs:160:40
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:166:1
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ╾ALLOC_ID╼                                     │ ╾──╼
+           }
+
+note: erroneous constant used
+  --> $DIR/raw-bytes.rs:166:42
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:170:1
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ╾ALLOC_ID╼                                     │ ╾──╼
+           }
+
+note: erroneous constant used
+  --> $DIR/raw-bytes.rs:170:42
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:175:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:179:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:183:1
+   |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:186:1
+   |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:190:1
+   |
+LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:194:1
+   |
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 00 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:196:1
+   |
+LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:201:1
+   |
+LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               00 10 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:205:1
+   |
+LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               09 00 00 00 03 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:209:1
+   |
+LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
+   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               01 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:210:1
+   |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
+   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               01 00 00 00 01 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:211:1
+   |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
+   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               01 00 00 00 2a 00 00 00                         │ ....*...
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:215:1
+   |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:218:1
+   |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:221:1
+   |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:225:1
+   |
+LL | pub static S7: &[u16] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID+0x2╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:232:1
+   |
+LL | pub static R4: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:237:1
+   |
+LL | pub static R5: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:242:1
+   |
+LL | pub static R6: &[bool] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
+           }
+
+error: aborting due to 52 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/raw-bytes.64bit.stderr b/src/test/ui/consts/const-eval/raw-bytes.64bit.stderr
new file mode 100644 (file)
index 0000000..e4c5e62
--- /dev/null
@@ -0,0 +1,596 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:20:1
+   |
+LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               01 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:28:1
+   |
+LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:42:1
+   |
+LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               01                                              │ .
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:44:1
+   |
+LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               03                                              │ .
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:50:1
+   |
+LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               78 00 00 00 ff ff ff ff                         │ x.......
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:54:1
+   |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:57:1
+   |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               00                                              │ .
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:59:1
+   |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:65:1
+   |
+LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               2a 00 00 00                                     │ *...
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:71:1
+   |
+LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               14 00 00 00                                     │ ....
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:74:1
+   |
+LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:82:1
+   |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               ╾ALLOC_ID╼                         │ ╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:86:1
+   |
+LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               ╾ALLOC_ID╼                         │ ╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:90:1
+   |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:93:1
+   |
+LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:96:1
+   |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               39 05 00 00 00 00 00 00                         │ 9.......
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:99:1
+   |
+LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               39 05 00 00 00 00 00 00                         │ 9.......
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:102:1
+   |
+LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:104:1
+   |
+LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               0d 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:106:1
+   |
+LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               ╾ALLOC_ID╼                         │ ╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:112:1
+   |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               01 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:137:1
+   |
+LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:139:1
+   |
+LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:141:1
+   |
+LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:144:1
+   |
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:146:1
+   |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:148:1
+   |
+LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:152:1
+   |
+LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:154:1
+   |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:157:1
+   |
+LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:160:1
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               ╾ALLOC_ID╼                         │ ╾──────╼
+           }
+
+note: erroneous constant used
+  --> $DIR/raw-bytes.rs:160:40
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:166:1
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               ╾ALLOC_ID╼                         │ ╾──────╼
+           }
+
+note: erroneous constant used
+  --> $DIR/raw-bytes.rs:166:42
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:170:1
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               ╾ALLOC_ID╼                         │ ╾──────╼
+           }
+
+note: erroneous constant used
+  --> $DIR/raw-bytes.rs:170:42
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:175:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:179:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:183:1
+   |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:186:1
+   |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:190:1
+   |
+LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:194:1
+   |
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:196:1
+   |
+LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:201:1
+   |
+LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:205:1
+   |
+LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:209:1
+   |
+LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
+   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               01 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:210:1
+   |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
+   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:211:1
+   |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
+   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*.......
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:215:1
+   |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:218:1
+   |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:221:1
+   |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:225:1
+   |
+LL | pub static S7: &[u16] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:232:1
+   |
+LL | pub static R4: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:237:1
+   |
+LL | pub static R5: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:242:1
+   |
+LL | pub static R6: &[bool] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error: aborting due to 52 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/raw-bytes.rs b/src/test/ui/consts/const-eval/raw-bytes.rs
new file mode 100644 (file)
index 0000000..6c1238c
--- /dev/null
@@ -0,0 +1,263 @@
+// stderr-per-bitwidth
+// ignore-endian-big
+// ignore-tidy-linelength
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// normalize-stderr-test "alloc\d+" -> "allocN"
+#![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)]
+#![allow(invalid_value)]
+
+use std::mem;
+use std::alloc::Layout;
+use std::ptr::NonNull;
+use std::num::{NonZeroU8, NonZeroUsize};
+use std::slice::{from_ptr_range, from_raw_parts};
+
+#[repr(usize)]
+#[derive(Copy, Clone)]
+enum Enum {
+    A = 0,
+}
+const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
+//~^ ERROR is undefined behavior
+
+#[repr(usize)]
+#[derive(Copy, Clone)]
+enum Enum2 {
+    A = 2,
+}
+const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
+//~^ ERROR is undefined behavior
+
+#[derive(Copy, Clone)]
+enum Never {}
+
+// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do*
+// have a discriminant.
+enum UninhDiscriminant {
+    A,
+    B(!),
+    C,
+    D(Never),
+}
+const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
+//~^ ERROR is undefined behavior
+const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
+//~^ ERROR is undefined behavior
+
+// Invalid enum field content (mostly to test printing of paths for enum tuple
+// variants and tuples).
+// Need to create something which does not clash with enum layout optimizations.
+const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
+//~^ ERROR is undefined behavior
+
+
+const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+//~^ ERROR it is undefined behavior to use this value
+const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+#[rustc_layout_scalar_valid_range_start(10)]
+#[rustc_layout_scalar_valid_range_end(30)]
+struct RestrictedRange1(u32);
+const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+//~^ ERROR it is undefined behavior to use this value
+
+#[rustc_layout_scalar_valid_range_start(30)]
+#[rustc_layout_scalar_valid_range_end(10)]
+struct RestrictedRange2(u32);
+const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+//~^ ERROR it is undefined behavior to use this value
+    let x: &dyn Send = &42;
+    let meta = std::ptr::metadata(x);
+    mem::transmute((0_usize, meta))
+};
+
+
+const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+//~^ ERROR it is undefined behavior to use this value
+//~| constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+
+const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+//~^ ERROR it is undefined behavior to use this value
+//~| constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+
+const NULL: &u16 = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+//~^ ERROR it is undefined behavior to use this value
+const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+//~^ ERROR it is undefined behavior to use this value
+const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+//~^ ERROR it is undefined behavior to use this value
+
+#[derive(Copy, Clone)]
+enum Bar {}
+
+const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+//~^ ERROR it is undefined behavior to use this value
+
+
+/// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error
+/// message.
+#[repr(transparent)]
+struct W<T>(T);
+
+#[repr(C)]
+union MaybeUninit<T: Copy> {
+    uninit: (),
+    init: T,
+}
+
+trait Trait {}
+impl Trait for bool {}
+
+// custom unsized type
+struct MyStr(str);
+
+// custom unsized type with sized fields
+struct MySlice<T: ?Sized>(bool, T);
+type MySliceBool = MySlice<[bool]>;
+
+const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+//~^ ERROR it is undefined behavior to use this value
+const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+//~^ ERROR it is undefined behavior to use this value
+const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+//~^ ERROR it is undefined behavior to use this value
+
+const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+//~^ ERROR it is undefined behavior to use this value
+const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+//~^ ERROR it is undefined behavior to use this value
+const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+//~^ ERROR: it is undefined behavior to use this value
+
+// # slice
+const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+//~^ ERROR it is undefined behavior to use this value
+const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+//~^ ERROR it is undefined behavior to use this value
+// bad slice box: length too big
+const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+//~^ ERROR it is undefined behavior to use this value
+// bad data *inside* the slice
+const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+//~^ ERROR it is undefined behavior to use this value
+//~| constant
+
+
+// bad: sized field is not okay
+const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+//~^ ERROR it is undefined behavior to use this value
+//~| constant
+// bad: unsized part is not okay
+const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+//~^ ERROR it is undefined behavior to use this value
+//~| constant
+
+// bad trait object
+const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+// bad trait object
+const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+// bad trait object
+const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a vtable
+// bad data *inside* the trait object
+const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+//~^ ERROR it is undefined behavior to use this value
+//~| expected a boolean
+
+const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+//~^ ERROR it is undefined behavior to use this value
+const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+//~^ ERROR it is undefined behavior to use this value
+
+
+// not ok, since alignment needs to be non-zero.
+const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+//~^ ERROR it is undefined behavior to use this value
+
+// not ok, since alignment needs to be a power of two.
+const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
+//~^ ERROR it is undefined behavior to use this value
+
+
+const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
+const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
+const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior
+
+
+// Reading uninitialized  data
+pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+//~^ ERROR: it is undefined behavior to use this value
+// Reinterpret pointers as integers (UB in CTFE.)
+pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
+//~^ ERROR: it is undefined behavior to use this value
+// Layout mismatch
+pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+//~^ ERROR: it is undefined behavior to use this value
+
+// Reading padding is not ok
+pub static S7: &[u16] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = (&D2 as *const Struct as *const u16).add(1);
+
+    from_raw_parts(ptr, 4)
+};
+
+pub static R4: &[u8] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = (&D1) as *const mem::MaybeUninit<&u32> as *const u8;
+    from_ptr_range(ptr..ptr.add(1))
+};
+pub static R5: &[u8] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = &D3 as *const &u32;
+    from_ptr_range(ptr.cast()..ptr.add(1).cast())
+};
+pub static R6: &[bool] = unsafe {
+    //~^ ERROR: it is undefined behavior to use this value
+    let ptr = &D0 as *const u32 as *const bool;
+    from_ptr_range(ptr..ptr.add(4))
+};
+
+const D0: u32 = 0x11111111; // Constant chosen for endianness-independent behavior.
+const D1: mem::MaybeUninit<&u32> = mem::MaybeUninit::uninit();
+const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
+const D3: &u32 = &42;
+
+#[repr(C)]
+struct Struct {
+    a: u8,
+    // _pad: [mem::MaybeUninit<u8>; 3]
+    b: u32,
+    c: u16,
+    d: u8,
+    // _pad: [mem::MaybeUninit<u8>; 1]
+}
+
+fn main() {}
index 93bc96e67674915f6b4a5c8d1807f1dfda88ceb0..2d86bd88f1c8834dd05b0fe7c86ac59bfc6fd07e 100644 (file)
@@ -1,16 +1,16 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:24:1
+  --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               01 00 00 00                                     │ ....
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:27:1
+  --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -19,7 +19,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:30:1
+  --> $DIR/ub-enum.rs:33:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -28,18 +28,18 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:42:1
+  --> $DIR/ub-enum.rs:45:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               00 00 00 00                                     │ ....
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:44:1
+  --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -48,7 +48,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:47:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -57,13 +57,13 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:56:42
+  --> $DIR/ub-enum.rs:59:42
    |
 LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:61:1
+  --> $DIR/ub-enum.rs:64:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -72,46 +72,46 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:78:1
+  --> $DIR/ub-enum.rs:81:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 1, align: 1) {
-               01                                              │ .
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:80:1
+  --> $DIR/ub-enum.rs:83:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 1, align: 1) {
-               03                                              │ .
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:88:1
+  --> $DIR/ub-enum.rs:91:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               78 00 00 00 ff ff ff ff                         │ x.......
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:93:77
+  --> $DIR/ub-enum.rs:96:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:95:77
+  --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
index 280ba25a83ca8fe25e98130e3e34e37b108ffdf8..a89d7ec5f6d44cb7824d0d7d7ab4aa783231c7f3 100644 (file)
@@ -1,16 +1,16 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:24:1
+  --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               01 00 00 00 00 00 00 00                         │ ........
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:27:1
+  --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -19,7 +19,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:30:1
+  --> $DIR/ub-enum.rs:33:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -28,18 +28,18 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:42:1
+  --> $DIR/ub-enum.rs:45:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               00 00 00 00 00 00 00 00                         │ ........
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:44:1
+  --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -48,7 +48,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:47:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -57,13 +57,13 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:56:42
+  --> $DIR/ub-enum.rs:59:42
    |
 LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:61:1
+  --> $DIR/ub-enum.rs:64:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -72,46 +72,46 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:78:1
+  --> $DIR/ub-enum.rs:81:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 1, align: 1) {
-               01                                              │ .
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:80:1
+  --> $DIR/ub-enum.rs:83:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 1, align: 1) {
-               03                                              │ .
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:88:1
+  --> $DIR/ub-enum.rs:91:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               78 00 00 00 ff ff ff ff                         │ x.......
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:93:77
+  --> $DIR/ub-enum.rs:96:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-enum.rs:95:77
+  --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
index 6935be2f92fe68a246e3f29e325ed77656938dd7..8f26d9a00d71bf5dee97997dd6177e415e49ba54 100644 (file)
@@ -1,4 +1,7 @@
 // stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![feature(never_type)]
 #![allow(invalid_value)]
 
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr
deleted file mode 100644 (file)
index b24e0cc..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:12:1
-   |
-LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               00 00 00 00                                     │ ....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-nonnull.rs:18:30
-   |
-LL |     let out_of_bounds_ptr = &ptr[255];
-   |                              ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:22:1
-   |
-LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 1, align: 1) {
-               00                                              │ .
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:24:1
-   |
-LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               00 00 00 00                                     │ ....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-nonnull.rs:32:36
-   |
-LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:41:1
-   |
-LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               2a 00 00 00                                     │ *...
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:47:1
-   |
-LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               14 00 00 00                                     │ ....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:50:1
-   |
-LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 ╾─alloc26─╼                         │ ....╾──╼
-           }
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr
deleted file mode 100644 (file)
index 92b8d01..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:12:1
-   |
-LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-nonnull.rs:18:30
-   |
-LL |     let out_of_bounds_ptr = &ptr[255];
-   |                              ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:22:1
-   |
-LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 1, align: 1) {
-               00                                              │ .
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:24:1
-   |
-LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-nonnull.rs:32:36
-   |
-LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:41:1
-   |
-LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               2a 00 00 00                                     │ *...
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:47:1
-   |
-LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               14 00 00 00                                     │ ....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-nonnull.rs:50:1
-   |
-LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               00 00 00 00 00 00 00 00 ╾───────alloc26───────╼ │ ........╾──────╼
-           }
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
index 49092582267c8c9e4cd233044b7ade02c47a06e6..a64b3a74cf6c0c0145165a50a3f280a88b39d4fc 100644 (file)
@@ -1,4 +1,6 @@
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![feature(rustc_attrs, ptr_metadata)]
 #![allow(invalid_value)] // make sure we cannot allow away the errors tested here
 
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr
new file mode 100644 (file)
index 0000000..9616487
--- /dev/null
@@ -0,0 +1,81 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-nonnull.rs:14:1
+   |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-nonnull.rs:20:30
+   |
+LL |     let out_of_bounds_ptr = &ptr[255];
+   |                              ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-nonnull.rs:24:1
+   |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-nonnull.rs:26:1
+   |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-nonnull.rs:34:36
+   |
+LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-nonnull.rs:43:1
+   |
+LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-nonnull.rs:49:1
+   |
+LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-nonnull.rs:52:1
+   |
+LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
deleted file mode 100644 (file)
index a0a8d76..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:14:1
-   |
-LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc3──╼                                     │ ╾──╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:18:1
-   |
-LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc7──╼                                     │ ╾──╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:22:1
-   |
-LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               00 00 00 00                                     │ ....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:25:1
-   |
-LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               00 00 00 00                                     │ ....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:32:1
-   |
-LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:35:39
-   |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:35:38
-   |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:38:86
-   |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:38:85
-   |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:41:1
-   |
-LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               39 05 00 00                                     │ 9...
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:44:1
-   |
-LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               39 05 00 00                                     │ 9...
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:47:41
-   |
-LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:51:1
-   |
-LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               00 00 00 00                                     │ ....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:53:38
-   |
-LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:56:1
-   |
-LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               0d 00 00 00                                     │ ....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:58:1
-   |
-LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc41─╼                                     │ ╾──╼
-           }
-
-error: accessing memory with alignment 1, but alignment 4 is required
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:65:5
-   |
-LL |     ptr.read();
-   |     ^^^^^^^^^^
-   = note: `#[deny(invalid_alignment)]` on by default
-
-error: aborting due to 15 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-Future incompatibility report: Future breakage diagnostic:
-error: accessing memory with alignment 1, but alignment 4 is required
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:65:5
-   |
-LL |     ptr.read();
-   |     ^^^^^^^^^^
-   = note: `#[deny(invalid_alignment)]` on by default
-
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
deleted file mode 100644 (file)
index d53b446..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:14:1
-   |
-LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc3────────╼                         │ ╾──────╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:18:1
-   |
-LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc7────────╼                         │ ╾──────╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:22:1
-   |
-LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:25:1
-   |
-LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:32:1
-   |
-LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:35:39
-   |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:35:38
-   |
-LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:38:86
-   |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-note: erroneous constant used
-  --> $DIR/ub-ref-ptr.rs:38:85
-   |
-LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:41:1
-   |
-LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               39 05 00 00 00 00 00 00                         │ 9.......
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:44:1
-   |
-LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               39 05 00 00 00 00 00 00                         │ 9.......
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:47:41
-   |
-LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:51:1
-   |
-LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               00 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-ref-ptr.rs:53:38
-   |
-LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:56:1
-   |
-LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               0d 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-ref-ptr.rs:58:1
-   |
-LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc41───────╼                         │ ╾──────╼
-           }
-
-error: accessing memory with alignment 1, but alignment 4 is required
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:65:5
-   |
-LL |     ptr.read();
-   |     ^^^^^^^^^^
-   = note: `#[deny(invalid_alignment)]` on by default
-
-error: aborting due to 15 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
-Future incompatibility report: Future breakage diagnostic:
-error: accessing memory with alignment 1, but alignment 4 is required
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:65:5
-   |
-LL |     ptr.read();
-   |     ^^^^^^^^^^
-   = note: `#[deny(invalid_alignment)]` on by default
-
index b0fc3c196a49fc3457915955dd277d352d6154c0..369e4519407fd24f647f27fe28a51195d3e2b068 100644 (file)
@@ -1,5 +1,7 @@
 // ignore-tidy-linelength
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![allow(invalid_value)]
 #![feature(const_ptr_read)]
 
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.stderr
new file mode 100644 (file)
index 0000000..ce61880
--- /dev/null
@@ -0,0 +1,186 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:16:1
+   |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:20:1
+   |
+LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:24:1
+   |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:27:1
+   |
+LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-ref-ptr.rs:34:1
+   |
+LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-ref-ptr.rs:37:39
+   |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+note: erroneous constant used
+  --> $DIR/ub-ref-ptr.rs:37:38
+   |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-ref-ptr.rs:40:86
+   |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+   |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+note: erroneous constant used
+  --> $DIR/ub-ref-ptr.rs:40:85
+   |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+   |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:43:1
+   |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:46:1
+   |
+LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-ref-ptr.rs:49:41
+   |
+LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:53:1
+   |
+LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-ref-ptr.rs:55:38
+   |
+LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:58:1
+   |
+LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-ref-ptr.rs:60:1
+   |
+LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:67:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+  --> $DIR/ub-ref-ptr.rs:67:5
+   |
+LL |     ptr.read();
+   |     ^^^^^^^^^^
+   = note: `#[deny(invalid_alignment)]` on by default
+
diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr
deleted file mode 100644 (file)
index 7d32322..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:14:1
-   |
-LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:17:1
-   |
-LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               01 00 00 00                                     │ ....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:20:1
-   |
-LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr
deleted file mode 100644 (file)
index 2b7659f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:14:1
-   |
-LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:17:1
-   |
-LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               01 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-uninhabit.rs:20:1
-   |
-LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
index 213f15b79174e95cafb8b799591d713cd792bed9..4c4ef216d8628b69a34ccd6a7b7690fe2038541b 100644 (file)
@@ -1,4 +1,6 @@
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 
 use std::mem;
 
diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr
new file mode 100644 (file)
index 0000000..0ae376d
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-uninhabit.rs:16:1
+   |
+LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-uninhabit.rs:19:1
+   |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-uninhabit.rs:22:1
+   |
+LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
deleted file mode 100644 (file)
index 90a3dca..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:37:1
-   |
-LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:39:1
-   |
-LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:42:1
-   |
-LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:45:1
-   |
-LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:47:1
-   |
-LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ff ff ff ff                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:51:1
-   |
-LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:54:1
-   |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:61:1
-   |
-LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:68:1
-   |
-LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:71:1
-   |
-LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ff ff ff 7f                         │ ╾──╼....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:74:1
-   |
-LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:77:1
-   |
-LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ e7 03 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:80:1
-   |
-LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:84:1
-   |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾ALLOC_ID╼                                     │ ╾──╼
-           }
-
-note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:84:40
-   |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:91:1
-   |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾ALLOC_ID╼                                     │ ╾──╼
-           }
-
-note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:91:42
-   |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:95:1
-   |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾ALLOC_ID╼                                     │ ╾──╼
-           }
-
-note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:95:42
-   |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:103:1
-   |
-LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:112:1
-   |
-LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:116:1
-   |
-LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:120:1
-   |
-LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:123:57
-   |
-LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:126:57
-   |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:129:56
-   |
-LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:132:1
-   |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:137:1
-   |
-LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:142:1
-   |
-LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ 00 00 00 00                         │ ╾──╼....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:144:1
-   |
-LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
-           }
-
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:150:5
-   |
-LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
-
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:154:5
-   |
-LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error: aborting due to 29 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
deleted file mode 100644 (file)
index ab25303..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:37:1
-   |
-LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:39:1
-   |
-LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:42:1
-   |
-LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:45:1
-   |
-LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:47:1
-   |
-LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:51:1
-   |
-LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:54:1
-   |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:61:1
-   |
-LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:68:1
-   |
-LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:71:1
-   |
-LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:74:1
-   |
-LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:77:1
-   |
-LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:80:1
-   |
-LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:84:1
-   |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾ALLOC_ID╼                         │ ╾──────╼
-           }
-
-note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:84:40
-   |
-LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:91:1
-   |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾ALLOC_ID╼                         │ ╾──────╼
-           }
-
-note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:91:42
-   |
-LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:95:1
-   |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾ALLOC_ID╼                         │ ╾──────╼
-           }
-
-note: erroneous constant used
-  --> $DIR/ub-wide-ptr.rs:95:42
-   |
-LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:103:1
-   |
-LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:112:1
-   |
-LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:116:1
-   |
-LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:120:1
-   |
-LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:123:57
-   |
-LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:126:57
-   |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:129:56
-   |
-LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:132:1
-   |
-LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:137:1
-   |
-LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:142:1
-   |
-LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:144:1
-   |
-LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
-           }
-
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:150:5
-   |
-LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
-
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:154:5
-   |
-LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-
-error: aborting due to 29 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
index d12e5e2bed93ef20daa6f5b98b4cb27b3920146a..a765dc71273d735c9c7b5cc1065f3da16d3e4339 100644 (file)
@@ -1,10 +1,11 @@
-// stderr-per-bitwidth
 // ignore-tidy-linelength
 #![allow(unused)]
 
 use std::mem;
 
-// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 // normalize-stderr-test "offset \d+" -> "offset N"
 // normalize-stderr-test "alloc\d+" -> "allocN"
 // normalize-stderr-test "size \d+" -> "size N"
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
new file mode 100644 (file)
index 0000000..f38e791
--- /dev/null
@@ -0,0 +1,297 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:38:1
+   |
+LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:40:1
+   |
+LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:43:1
+   |
+LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:46:1
+   |
+LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:48:1
+   |
+LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:52:1
+   |
+LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:55:1
+   |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:62:1
+   |
+LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:69:1
+   |
+LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:72:1
+   |
+LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:75:1
+   |
+LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:78:1
+   |
+LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:81:1
+   |
+LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:85:1
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+note: erroneous constant used
+  --> $DIR/ub-wide-ptr.rs:85:40
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:92:1
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+note: erroneous constant used
+  --> $DIR/ub-wide-ptr.rs:92:42
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:96:1
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+note: erroneous constant used
+  --> $DIR/ub-wide-ptr.rs:96:42
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:104:1
+   |
+LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:113:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:117:1
+   |
+LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:121:1
+   |
+LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:124:57
+   |
+LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:127:57
+   |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-wide-ptr.rs:130:56
+   |
+LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:133:1
+   |
+LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:138:1
+   |
+LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:143:1
+   |
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:145:1
+   |
+LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ub-wide-ptr.rs:151:5
+   |
+LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ub-wide-ptr.rs:155:5
+   |
+LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
+
+error: aborting due to 29 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
index 4758ea4ae881815c63f125e76a489cd37eedbe8a..0dd18a55786ad34cdb3a2d2a5b6cc1ee57ab9eef 100644 (file)
@@ -21,12 +21,6 @@ note: erroneous constant used
 LL |     let _: &'static _ = &C;
    |                         ^^
 
-note: erroneous constant used
-  --> $DIR/invalid-union.rs:43:25
-   |
-LL |     let _: &'static _ = &C;
-   |                         ^^
-
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
index 22b85d20ce9dd9becf600d2940b5ff1191a8b87e..07f36ee283264dc9181a92f7de95e759313f83d9 100644 (file)
@@ -21,12 +21,6 @@ note: erroneous constant used
 LL |     let _: &'static _ = &C;
    |                         ^^
 
-note: erroneous constant used
-  --> $DIR/invalid-union.rs:43:25
-   |
-LL |     let _: &'static _ = &C;
-   |                         ^^
-
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
index 41b0816dc32af8dd4b7fc8a6d52d443b0ed0a200..34d8ee281cf8ce77e0432bfc90c1a06a644b3876 100644 (file)
@@ -20,7 +20,7 @@ LL | struct S<const S: (), const S: S = { S }>;
 help: add missing generic argument
    |
 LL | struct S<const S: (), const S: S<S> = { S }>;
-   |                                ~~~~
+   |                                 +++
 
 error[E0391]: cycle detected when computing type of `S::S`
   --> $DIR/issue-103790.rs:4:32
diff --git a/src/test/ui/consts/issue-83182.32bit.stderr b/src/test/ui/consts/issue-83182.32bit.stderr
deleted file mode 100644 (file)
index 2776e2b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/issue-83182.rs:5:1
-   |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾─alloc4──╼ 01 00 00 00                         │ ╾──╼....
-           }
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/issue-83182.64bit.stderr b/src/test/ui/consts/issue-83182.64bit.stderr
deleted file mode 100644 (file)
index 9e884ce..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/issue-83182.rs:5:1
-   |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾───────alloc4────────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
index 2536d2f08f288864cdcad95ded56a105f2fc8f2f..b62f903bdc27071e7d47e660c6da927a08e17044 100644 (file)
@@ -1,4 +1,6 @@
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 
 use std::mem;
 struct MyStr(str);
diff --git a/src/test/ui/consts/issue-83182.stderr b/src/test/ui/consts/issue-83182.stderr
new file mode 100644 (file)
index 0000000..1d578f9
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/issue-83182.rs:7:1
+   |
+LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
index 79efcd3f62eedb951a1a7d239e1ed2172a687a45..8c83df53dade5045fe3053cdc154fcfc313b567a 100644 (file)
@@ -1,23 +1,23 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/alloc.rs:9:1
+  --> $DIR/alloc.rs:12:1
    |
 LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 10 00 00 00 00 00 00                         │ ........
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/alloc.rs:13:1
+  --> $DIR/alloc.rs:16:1
    |
 LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               09 00 00 00 03 00 00 00                         │ ........
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error: aborting due to 2 previous errors
index cb477b72b312173d518b60aae687b2c764483a43..addedad17047a9be851b19c214554b4223fc157a 100644 (file)
@@ -1,23 +1,23 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/alloc.rs:9:1
+  --> $DIR/alloc.rs:12:1
    |
 LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/alloc.rs:13:1
+  --> $DIR/alloc.rs:16:1
    |
 LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
            }
 
 error: aborting due to 2 previous errors
index 708b954e84aeae95b429ef35dc545e2f17152bac..9abf35d63d30ac9d585603f895034d5f43827844 100644 (file)
@@ -1,5 +1,8 @@
 // stderr-per-bitwidth
 // ignore-debug (the debug assertions change the error)
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 use std::alloc::Layout;
 
 // ok
diff --git a/src/test/ui/consts/validate_never_arrays.32bit.stderr b/src/test/ui/consts/validate_never_arrays.32bit.stderr
deleted file mode 100644 (file)
index a5dbc71..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_never_arrays.rs:4:1
-   |
-LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 4, align: 4) {
-               01 00 00 00                                     │ ....
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_never_arrays.rs:7:1
-   |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               01 00 00 00 01 00 00 00                         │ ........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_never_arrays.rs:8:1
-   |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
-   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               01 00 00 00 2a 00 00 00                         │ ....*...
-           }
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/validate_never_arrays.64bit.stderr b/src/test/ui/consts/validate_never_arrays.64bit.stderr
deleted file mode 100644 (file)
index dac4e20..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_never_arrays.rs:4:1
-   |
-LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 8) {
-               01 00 00 00 00 00 00 00                         │ ........
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_never_arrays.rs:7:1
-   |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_never_arrays.rs:8:1
-   |
-LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
-   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 16, align: 8) {
-               01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*.......
-           }
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
index a02e386c66c4d3550442cdd9edd6906f9b304999..f96ca6839265ef2831734dada44987007daf5aaa 100644 (file)
@@ -1,4 +1,6 @@
-// stderr-per-bitwidth
+// Strip out raw byte dumps to make comparison platform-independent:
+// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![feature(never_type)]
 
 const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr
new file mode 100644 (file)
index 0000000..12090e4
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validate_never_arrays.rs:6:1
+   |
+LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
+   | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1]
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validate_never_arrays.rs:9:1
+   |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
+   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validate_never_arrays.rs:10:1
+   |
+LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
+   | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
index a00a19e46d519fbad8d1c876250fbedf73503b7b..bd9c8483ec29ed171d7625d4bb7c654a51470738 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags:-C extra-filename=-1
+// no-prefer-dynamic
 #![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
index 71cc0a12ea37946301e39ceb594836edc93cec69..bd0f08f45b633ce778d9136ce622a64664b4863a 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags:-C extra-filename=-2
+// no-prefer-dynamic
 #![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
index 921687d4c3bffd199e3c73b0264a1c811e23eca7..1226c2fbb461eee92efa1ada48802562eed83ff1 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags:-C extra-filename=-3
+// no-prefer-dynamic
 #![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
index f4795e9536af70cd32171c878ae7a71dcf5b5762..f5477f244dd8f033f8d2123bfa87bace9687b8a2 100644 (file)
@@ -9,7 +9,6 @@
 // NOTE: This test is duplicated at `src/test/ui/error-codes/E0464.rs`.
 
 extern crate crateresolve1;
-//~^ ERROR multiple matching crates for `crateresolve1`
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
 
-fn main() {
-}
+fn main() {}
index 0d7538eafd8127ddef34779fd6c6cb6b8a8b278c..7b840b52628f1a413d1ff894f818db14159e1263 100644 (file)
@@ -1,13 +1,12 @@
-error[E0464]: multiple matching crates for `crateresolve1`
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
   --> $DIR/crateresolve1.rs:11:1
    |
 LL | extern crate crateresolve1;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: candidates:
-           crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.somelib
-           crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.somelib
-           crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.somelib
+   = note: candidate #1: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.somelib
+   = note: candidate #2: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.somelib
+   = note: candidate #3: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.somelib
 
 error: aborting due to previous error
 
index 5a4fee7ed6afad19db5227d8980bee1192145331..0774c0dfd329dff8da64d810935f913362bb8791 100644 (file)
@@ -8,7 +8,6 @@
 // normalize-stderr-test: "\\\?\\" -> ""
 
 extern crate crateresolve2;
-//~^ ERROR multiple matching crates for `crateresolve2`
+//~^ ERROR multiple candidates for `rmeta` dependency `crateresolve2` found
 
-fn main() {
-}
+fn main() {}
index afd3702de7f73895b77052591bebf930fdbe16a7..a36f4f02265b7db3ffdce980b6846786d16d8e17 100644 (file)
@@ -1,13 +1,12 @@
-error[E0464]: multiple matching crates for `crateresolve2`
+error[E0464]: multiple candidates for `rmeta` dependency `crateresolve2` found
   --> $DIR/crateresolve2.rs:10:1
    |
 LL | extern crate crateresolve2;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: candidates:
-           crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta
-           crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta
-           crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta
+   = note: candidate #1: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta
+   = note: candidate #2: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta
+   = note: candidate #3: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta
 
 error: aborting due to previous error
 
index 9562d94509ea8f479e44caaf578337b9a78aae1f..1670da55957d073097397d628acc8f0225dea82d 100644 (file)
@@ -1,26 +1,35 @@
 error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable
   --> $DIR/issue-35937.rs:7:5
    |
-LL |     let f = Foo { v: Vec::new() };
-   |         - help: consider changing this to be mutable: `mut f`
 LL |     f.v.push("cat".to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = Foo { v: Vec::new() };
+   |         +++
 
 error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
   --> $DIR/issue-35937.rs:16:5
    |
-LL |     let s = S { x: 42 };
-   |         - help: consider changing this to be mutable: `mut s`
 LL |     s.x += 1;
    |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut s = S { x: 42 };
+   |         +++
 
 error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
   --> $DIR/issue-35937.rs:20:5
    |
-LL | fn bar(s: S) {
-   |        - help: consider changing this to be mutable: `mut s`
 LL |     s.x += 1;
    |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn bar(mut s: S) {
+   |        +++
 
 error: aborting due to 3 previous errors
 
index dd193458b3726bc8294c046191ddbee6ef279246..74fb1c2eca30771bce01691c7cd03514baa9b7d9 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
   --> $DIR/issue-38147-1.rs:17:9
    |
-LL |     fn f(&self) {
-   |          ----- help: consider changing this to be a mutable reference: `&mut self`
 LL |         self.s.push('x');
    |         ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn f(&mut self) {
+   |          ~~~~~~~~~
 
 error: aborting due to previous error
 
index a2d162f08a173cbf2d56be888ccb470da09eb97b..d3339989361694c840542ea437695f992cc189bb 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*f.s` as mutable, as it is behind a `&` reference
   --> $DIR/issue-38147-4.rs:6:5
    |
-LL | fn f(x: usize, f: &Foo) {
-   |                   ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>`
 LL |     f.s.push('x');
    |     ^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn f(x: usize, f: &mut Foo<'_>) {
+   |                   ~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 68180eaee036c41f1fa7d80fa88fead6bb498250..8dc0512a9453dbafd54f2d28c73803ba9abcee84 100644 (file)
 error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
   --> $DIR/issue-39544.rs:11:13
    |
-LL |     let z = Z { x: X::Y };
-   |         - help: consider changing this to be mutable: `mut z`
 LL |     let _ = &mut z.x;
    |             ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut z = Z { x: X::Y };
+   |         +++
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:16:17
    |
-LL |     fn foo<'z>(&'z self) {
-   |                -------- help: consider changing this to be a mutable reference: `&'z mut self`
 LL |         let _ = &mut self.x;
    |                 ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo<'z>(&'z mut self) {
+   |                ~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:20:17
    |
-LL |     fn foo1(&self, other: &Z) {
-   |             ----- help: consider changing this to be a mutable reference: `&mut self`
 LL |         let _ = &mut self.x;
    |                 ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo1(&mut self, other: &Z) {
+   |             ~~~~~~~~~
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:21:17
    |
-LL |     fn foo1(&self, other: &Z) {
-   |                           -- help: consider changing this to be a mutable reference: `&mut Z`
-LL |         let _ = &mut self.x;
 LL |         let _ = &mut other.x;
    |                 ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo1(&self, other: &mut Z) {
+   |                           ~~~~~~
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:25:17
    |
-LL |     fn foo2<'a>(&'a self, other: &Z) {
-   |                 -------- help: consider changing this to be a mutable reference: `&'a mut self`
 LL |         let _ = &mut self.x;
    |                 ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo2<'a>(&'a mut self, other: &Z) {
+   |                 ~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:26:17
    |
-LL |     fn foo2<'a>(&'a self, other: &Z) {
-   |                                  -- help: consider changing this to be a mutable reference: `&mut Z`
-LL |         let _ = &mut self.x;
 LL |         let _ = &mut other.x;
    |                 ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo2<'a>(&'a self, other: &mut Z) {
+   |                                  ~~~~~~
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:30:17
    |
-LL |     fn foo3<'a>(self: &'a Self, other: &Z) {
-   |                       -------- help: consider changing this to be a mutable reference: `&'a mut Self`
 LL |         let _ = &mut self.x;
    |                 ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo3<'a>(self: &'a mut Self, other: &Z) {
+   |                       ~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:31:17
    |
-LL |     fn foo3<'a>(self: &'a Self, other: &Z) {
-   |                                        -- help: consider changing this to be a mutable reference: `&mut Z`
-LL |         let _ = &mut self.x;
 LL |         let _ = &mut other.x;
    |                 ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo3<'a>(self: &'a Self, other: &mut Z) {
+   |                                        ~~~~~~
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:35:17
    |
-LL |     fn foo4(other: &Z) {
-   |                    -- help: consider changing this to be a mutable reference: `&mut Z`
 LL |         let _ = &mut other.x;
    |                 ^^^^^^^^^^^^ `other` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo4(other: &mut Z) {
+   |                    ~~~~~~
 
 error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
   --> $DIR/issue-39544.rs:41:13
    |
-LL | pub fn with_arg(z: Z, w: &Z) {
-   |                 - help: consider changing this to be mutable: `mut z`
 LL |     let _ = &mut z.x;
    |             ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | pub fn with_arg(mut z: Z, w: &Z) {
+   |                 +++
 
 error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:42:13
    |
-LL | pub fn with_arg(z: Z, w: &Z) {
-   |                          -- help: consider changing this to be a mutable reference: `&mut Z`
-LL |     let _ = &mut z.x;
 LL |     let _ = &mut w.x;
    |             ^^^^^^^^ `w` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | pub fn with_arg(z: Z, w: &mut Z) {
+   |                          ~~~~~~
 
 error[E0594]: cannot assign to `*x.0`, which is behind a `&` reference
   --> $DIR/issue-39544.rs:48:5
index 67703a1497f50c7e60d6ebde2f621e9bd917a065..aadd698891edc7a5f9218c3491bdab65ac4cb407 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*buf` as mutable, as it is behind a `&` reference
   --> $DIR/issue-40823.rs:3:5
    |
-LL |     let mut buf = &[1, 2, 3, 4];
-   |                   ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]`
 LL |     buf.iter_mut();
    |     ^^^^^^^^^^^^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let mut buf = &mut [1, 2, 3, 4];
+   |                   ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/drop/issue-2734.rs b/src/test/ui/drop/issue-2734.rs
new file mode 100644 (file)
index 0000000..df4f394
--- /dev/null
@@ -0,0 +1,22 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+// pretty-expanded FIXME #23616
+
+trait hax {
+    fn dummy(&self) { }
+}
+impl<A> hax for A { }
+
+fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
+    Box::new(x) as Box<dyn hax+'static>
+}
+
+fn deadcode() {
+    perform_hax(Box::new("deadcode".to_string()));
+}
+
+pub fn main() {
+    let _ = perform_hax(Box::new(42));
+}
index 82169ee01bedd7b76ede76f5bc29d0f5f8053391..5cec2bcb0387210361ea9a9901b0ee1f44c8cdca 100644 (file)
@@ -1,13 +1,8 @@
 error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
   --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:21:1
    |
-LL | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
-LL | |
-LL | |
-LL | |     // (unsafe to access self.1  due to #[may_dangle] on A)
-LL | |     fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
-LL | | }
-   | |_^
+LL | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
 help: add `unsafe` to this trait implementation
@@ -18,13 +13,8 @@ LL | unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
 error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
   --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:27:1
    |
-LL | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
-LL | |
-LL | |
-LL | |     // (unsafe to access self.1 due to #[may_dangle] on 'a)
-LL | |     fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
-LL | | }
-   | |_^
+LL | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
 help: add `unsafe` to this trait implementation
diff --git a/src/test/ui/dropck/issue-34053.rs b/src/test/ui/dropck/issue-34053.rs
new file mode 100644 (file)
index 0000000..fa23ae8
--- /dev/null
@@ -0,0 +1,30 @@
+// run-pass
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+struct A(i32);
+
+impl Drop for A {
+    fn drop(&mut self) {
+        // update global drop count
+        DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+    }
+}
+
+static FOO: A = A(123);
+const BAR: A = A(456);
+
+impl A {
+    const BAZ: A = A(789);
+}
+
+fn main() {
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
+    assert_eq!(&FOO.0, &123);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
+    assert_eq!(BAR.0, 456);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 1);
+    assert_eq!(A::BAZ.0, 789);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
+}
index 983d7bf6e7e9cdc7e3d7053534651ca41b95180b..53c2cbeac3269a4958578d8240d86469be19110b 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 6b6fc55d8053eb71861505f62c24082816a29b02..62e28efab5820f73b90931e1041d45264a839d0a 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = 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
index fdf74aa7efe08de048a8cec8aff22e234b9e4e30..cb9c78158146156d3cd37a972c51b046534d21bd 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 933c133831ad330412c96bead9ea040debbbcabc..bcd014f8dc32d842823d960f24ef9a1e10c57a41 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 2767e9478e2e8df8df4d0ed7e1ea8d96d0b92853..c3449b6278bac5b4a0b1ea90641dd8c38854c46c 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: dyn* trait objects are unstable
 LL | pub fn dyn_star_parameter(_: &dyn* Send) {
    |                               ^^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = help: add `#![feature(dyn_star)]` to the crate attributes to enable
 
 error: aborting due to previous error
index 687d7db046478b5d0b551ae3754a712ca704b812..eb9c933055abc190d054fcc52740cd592fbd224e 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: dyn* trait objects are unstable
 LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
    |                ^^^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = help: add `#![feature(dyn_star)]` to the crate attributes to enable
 
 error[E0658]: dyn* trait objects are unstable
@@ -13,7 +13,7 @@ error[E0658]: dyn* trait objects are unstable
 LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
    |                                  ^^^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = help: add `#![feature(dyn_star)]` to the crate attributes to enable
 
 error[E0606]: casting `usize` as `dyn* Debug` is invalid
index 2fc751b3b4a1efbff854a2355448c7922ac284fc..c7f1a4b9ae11366bc78566a390ae7c24cf1b9475 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star, trait_upcasting)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0308]: mismatched types
index e000351a68f541d7057fbb4bc49708ef5722b0e2..9c265682904438ed928fe0cb2d2767b7bdf6c872 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 6a95f7754e68548d8abb417105c7bb88d2e62dbd..74ccd6a1889cd22c7028bb3f260b0f3c412f1bfd 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star, trait_upcasting)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = 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
diff --git a/src/test/ui/enum-discriminant/issue-72554.rs b/src/test/ui/enum-discriminant/issue-72554.rs
new file mode 100644 (file)
index 0000000..54f7e9a
--- /dev/null
@@ -0,0 +1,22 @@
+use std::collections::BTreeSet;
+
+#[derive(Hash)]
+pub enum ElemDerived {
+    //~^ ERROR recursive type `ElemDerived` has infinite size
+    A(ElemDerived)
+}
+
+
+pub enum Elem {
+    Derived(ElemDerived)
+}
+
+pub struct Set(BTreeSet<Elem>);
+
+impl Set {
+    pub fn into_iter(self) -> impl Iterator<Item = Elem> {
+        self.0.into_iter()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/enum-discriminant/issue-72554.stderr b/src/test/ui/enum-discriminant/issue-72554.stderr
new file mode 100644 (file)
index 0000000..d12be53
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `ElemDerived` has infinite size
+  --> $DIR/issue-72554.rs:4:1
+   |
+LL | pub enum ElemDerived {
+   | ^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     A(ElemDerived)
+   |       ----------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
+   |
+LL |     A(Box<ElemDerived>)
+   |       ++++           +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/error-codes/E0013.rs b/src/test/ui/error-codes/E0013.rs
new file mode 100644 (file)
index 0000000..9b3982a
--- /dev/null
@@ -0,0 +1,4 @@
+static X: i32 = 42;
+const Y: i32 = X; //~ ERROR constants cannot refer to statics [E0013]
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0013.stderr b/src/test/ui/error-codes/E0013.stderr
new file mode 100644 (file)
index 0000000..dc22053
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0013]: constants cannot refer to statics
+  --> $DIR/E0013.rs:2:16
+   |
+LL | const Y: i32 = X;
+   |                ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0013`.
diff --git a/src/test/ui/error-codes/E0015.rs b/src/test/ui/error-codes/E0015.rs
new file mode 100644 (file)
index 0000000..b021135
--- /dev/null
@@ -0,0 +1,8 @@
+fn create_some() -> Option<u8> {
+    Some(1)
+}
+
+const FOO: Option<u8> = create_some();
+//~^ ERROR cannot call non-const fn `create_some` in constants [E0015]
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0015.stderr b/src/test/ui/error-codes/E0015.stderr
new file mode 100644 (file)
index 0000000..ec1ce47
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `create_some` in constants
+  --> $DIR/E0015.rs:5:25
+   |
+LL | const FOO: Option<u8> = create_some();
+   |                         ^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
index 19439651394234071986e9fd56e3f16f9a4b1a12..289561bad8a0963a9b28a36b6b0334db00f72728 100644 (file)
@@ -1,13 +1,13 @@
 // compile-flags: -Z teach
-
 trait SomeTrait {
-    fn foo(); //~ associated function `foo` has no `self` parameter
+    fn foo(&self);
+}
+struct S;
+impl SomeTrait for S {
+    fn foo(&self) {}
 }
-
 fn main() {
-    let trait_obj: &dyn SomeTrait = SomeTrait;
-    //~^ ERROR expected value, found trait `SomeTrait`
-    //~| ERROR E0038
+    let trait_obj: &dyn SomeTrait = &S;
 
     let &invalid = trait_obj;
     //~^ ERROR E0033
index 3b68abbb4a0ba1c22a0d7e486c2e6164245190cb..31bc6719a562e59ec7a78b3e47d9512c522a1ca8 100644 (file)
@@ -1,31 +1,3 @@
-error[E0423]: expected value, found trait `SomeTrait`
-  --> $DIR/E0033-teach.rs:8:37
-   |
-LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
-   |                                     ^^^^^^^^^ not a value
-
-error[E0038]: the trait `SomeTrait` cannot be made into an object
-  --> $DIR/E0033-teach.rs:8:20
-   |
-LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
-   |                    ^^^^^^^^^^^^^^ `SomeTrait` cannot be made into an object
-   |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/E0033-teach.rs:4:8
-   |
-LL | trait SomeTrait {
-   |       --------- this trait cannot be made into an object...
-LL |     fn foo();
-   |        ^^^ ...because associated function `foo` has no `self` parameter
-help: consider turning `foo` into a method by giving it a `&self` argument
-   |
-LL |     fn foo(&self);
-   |            +++++
-help: alternatively, consider constraining `foo` so it does not apply to trait objects
-   |
-LL |     fn foo() where Self: Sized;
-   |              +++++++++++++++++
-
 error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
   --> $DIR/E0033-teach.rs:12:9
    |
@@ -36,7 +8,6 @@ LL |     let &invalid = trait_obj;
            
            You can read more about trait objects in the Trait Objects section of the Reference: https://doc.rust-lang.org/reference/types.html#trait-objects
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0033, E0038, E0423.
-For more information about an error, try `rustc --explain E0033`.
+For more information about this error, try `rustc --explain E0033`.
index e5f0530f45ff86ae0a5550512d394184db90fe58..bd6ec20722313a9c56170ca87161b21031fbb5e5 100644 (file)
@@ -1,11 +1,12 @@
 trait SomeTrait {
-    fn foo(); //~ associated function `foo` has no `self` parameter
+    fn foo(&self);
+}
+struct S;
+impl SomeTrait for S {
+    fn foo(&self) {}
 }
-
 fn main() {
-    let trait_obj: &dyn SomeTrait = SomeTrait;
-    //~^ ERROR expected value, found trait `SomeTrait`
-    //~| ERROR E0038
+    let trait_obj: &dyn SomeTrait = &S;
 
     let &invalid = trait_obj;
     //~^ ERROR E0033
index f0645107831e0c9402807503d47dc7356daad3e5..ab2e780ee624d335bec00638975d1ac68b397efd 100644 (file)
@@ -1,38 +1,9 @@
-error[E0423]: expected value, found trait `SomeTrait`
-  --> $DIR/E0033.rs:6:37
-   |
-LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
-   |                                     ^^^^^^^^^ not a value
-
-error[E0038]: the trait `SomeTrait` cannot be made into an object
-  --> $DIR/E0033.rs:6:20
-   |
-LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
-   |                    ^^^^^^^^^^^^^^ `SomeTrait` cannot be made into an object
-   |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/E0033.rs:2:8
-   |
-LL | trait SomeTrait {
-   |       --------- this trait cannot be made into an object...
-LL |     fn foo();
-   |        ^^^ ...because associated function `foo` has no `self` parameter
-help: consider turning `foo` into a method by giving it a `&self` argument
-   |
-LL |     fn foo(&self);
-   |            +++++
-help: alternatively, consider constraining `foo` so it does not apply to trait objects
-   |
-LL |     fn foo() where Self: Sized;
-   |              +++++++++++++++++
-
 error[E0033]: type `&dyn SomeTrait` cannot be dereferenced
-  --> $DIR/E0033.rs:10:9
+  --> $DIR/E0033.rs:11:9
    |
 LL |     let &invalid = trait_obj;
    |         ^^^^^^^^ type `&dyn SomeTrait` cannot be dereferenced
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0033, E0038, E0423.
-For more information about an error, try `rustc --explain E0033`.
+For more information about this error, try `rustc --explain E0033`.
index 99d808c0d4b1e115947acdbf76c2e9f55f23b19c..68c308b15cc0868940017c27ffc69e380441deb8 100644 (file)
@@ -2,7 +2,7 @@ error[E0199]: implementing the trait `Bar` is not unsafe
   --> $DIR/E0199.rs:6:1
    |
 LL | unsafe impl Bar for Foo { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `unsafe` from this trait implementation
    |
index 1fd86aecee177a787d507289349ce8a10106d9b5..c70a2d4f3d1f132ec1671bc51928152adcf44660 100644 (file)
@@ -2,7 +2,7 @@ error[E0200]: the trait `Bar` requires an `unsafe impl` declaration
   --> $DIR/E0200.rs:5:1
    |
 LL | impl Bar for Foo { }
-   | ^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^
    |
    = note: the trait `Bar` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
 help: add `unsafe` to this trait implementation
index 3d615bd932f436fe42e5c529664424ded3959616..51c4c92addf2856b413d36a2a10864f2b3756abb 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `fancy_ref.num`, which is behind a `&` reference
   --> $DIR/E0389.rs:8:5
    |
-LL |     let fancy_ref = &(&mut fancy);
-   |                     ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
 LL |     fancy_ref.num = 6;
    |     ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let fancy_ref = &mut (&mut fancy);
+   |                     ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 969115a7d9774162b0dcb22f8c7a66afb8c38e7d..554f1ce72d9e87964bdaa5ddb617ff056fe86b28 100644 (file)
@@ -9,7 +9,6 @@
 // NOTE: This test is duplicated from `src/test/ui/crate-loading/crateresolve1.rs`.
 
 extern crate crateresolve1;
-//~^ ERROR multiple matching crates for `crateresolve1`
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
 
-fn main() {
-}
+fn main() {}
index 3d950ddd28ee00428abbff31ff17f6119ca7f273..574270f94a672a023e38527c455575bfebef2978 100644 (file)
@@ -1,13 +1,12 @@
-error[E0464]: multiple matching crates for `crateresolve1`
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
   --> $DIR/E0464.rs:11:1
    |
 LL | extern crate crateresolve1;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: candidates:
-           crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.somelib
-           crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.somelib
-           crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.somelib
+   = note: candidate #1: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.somelib
+   = note: candidate #2: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.somelib
+   = note: candidate #3: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.somelib
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0519.rs b/src/test/ui/error-codes/E0519.rs
new file mode 100644 (file)
index 0000000..269ffd6
--- /dev/null
@@ -0,0 +1,8 @@
+// no need to create a new aux file, we can use an existing.
+// aux-build: crateresolve1-1.rs
+
+// set same metadata as `crateresolve1`
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+extern crate crateresolve1; //~ ERROR E0519
diff --git a/src/test/ui/error-codes/E0519.stderr b/src/test/ui/error-codes/E0519.stderr
new file mode 100644 (file)
index 0000000..e24fc4a
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
+  --> $DIR/E0519.rs:8:1
+   |
+LL | extern crate crateresolve1;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0519`.
index 79bc258f1fae7a7605430fbfa344818374166b47..3f9aebcc8aeadca8739d4114b0956d42616beb6f 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/E0596.rs:3:13
    |
-LL |     let x = 1;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     let y = &mut x;
    |             ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 1;
+   |         +++
 
 error: aborting due to previous error
 
index 35a4b34fb0a4d457e77b2e5de653dbc75cb4f1a4..78341735e191a1fbea98c8862328fc397e13bae6 100644 (file)
@@ -21,6 +21,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
    |
 LL |     T: Into<&u32>,
    |             ^ explicit lifetime name needed here
+   |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+  --> $DIR/E0637.rs:13:8
+   |
+LL |     T: Into<&u32>,
+   |        ^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/error-codes/E0711.rs b/src/test/ui/error-codes/E0711.rs
new file mode 100644 (file)
index 0000000..7d2044a
--- /dev/null
@@ -0,0 +1,18 @@
+// copied from: src/test/ui/feature-gates/stability-attribute-consistency.rs
+
+#![feature(staged_api)]
+
+#![stable(feature = "stable_test_feature", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.0.0")]
+fn foo_stable_1_0_0() {}
+
+#[stable(feature = "foo", since = "1.29.0")]
+//~^ ERROR feature `foo` is declared stable since 1.29.0
+fn foo_stable_1_29_0() {}
+
+#[unstable(feature = "foo", issue = "none")]
+//~^ ERROR feature `foo` is declared unstable
+fn foo_unstable() {}
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0711.stderr b/src/test/ui/error-codes/E0711.stderr
new file mode 100644 (file)
index 0000000..f39cb4e
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0711]: feature `foo` is declared stable since 1.29.0, but was previously declared stable since 1.0.0
+  --> $DIR/E0711.rs:10:1
+   |
+LL | #[stable(feature = "foo", since = "1.29.0")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0711]: feature `foo` is declared unstable, but was previously declared stable
+  --> $DIR/E0711.rs:14:1
+   |
+LL | #[unstable(feature = "foo", issue = "none")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0711`.
index a00a19e46d519fbad8d1c876250fbedf73503b7b..bd9c8483ec29ed171d7625d4bb7c654a51470738 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags:-C extra-filename=-1
+// no-prefer-dynamic
 #![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
index 71cc0a12ea37946301e39ceb594836edc93cec69..bd0f08f45b633ce778d9136ce622a64664b4863a 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags:-C extra-filename=-2
+// no-prefer-dynamic
 #![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
index 921687d4c3bffd199e3c73b0264a1c811e23eca7..1226c2fbb461eee92efa1ada48802562eed83ff1 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags:-C extra-filename=-3
+// no-prefer-dynamic
 #![crate_name = "crateresolve1"]
 #![crate_type = "lib"]
 
index e4341e196877bb1252da5ee93924f5aeac0f6518..fdec072b8a864cb5ed72195e4e429ca9449bf6b6 100644 (file)
@@ -8,7 +8,6 @@
 
 fn main() {
     let p = Some(45).and_then({
-        //~^ expected a `FnOnce<({integer},)>` closure, found `Option<_>`
         |x| println!("doubling {}", x);
         Some(x * 2)
         //~^ ERROR: cannot find value `x` in this scope
index 2f9d10d70a2fea087ef955ca6a2ad9e22dcb4108..e8b34121b5f8d1f80fb731b5fa441b95828523b0 100644 (file)
@@ -1,29 +1,9 @@
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/ruby_style_closure.rs:13:14
+  --> $DIR/ruby_style_closure.rs:12:14
    |
 LL |         Some(x * 2)
    |              ^ not found in this scope
 
-error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<_>`
-  --> $DIR/ruby_style_closure.rs:10:31
-   |
-LL |       let p = Some(45).and_then({
-   |  ______________________--------_^
-   | |                      |
-   | |                      required by a bound introduced by this call
-LL | |
-LL | |         |x| println!("doubling {}", x);
-LL | |         Some(x * 2)
-   | |         ----------- this tail expression is of type `Option<_>`
-LL | |
-LL | |     });
-   | |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<_>`
-   |
-   = help: the trait `FnOnce<({integer},)>` is not implemented for `Option<_>`
-note: required by a bound in `Option::<T>::and_then`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0277, E0425.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/extern/issue-13655.rs b/src/test/ui/extern/issue-13655.rs
new file mode 100644 (file)
index 0000000..6dd1847
--- /dev/null
@@ -0,0 +1,32 @@
+// run-pass
+#![feature(fn_traits, unboxed_closures)]
+use std::ops::Fn;
+
+struct Foo<T>(T);
+
+impl<T: Copy> Fn<()> for Foo<T> {
+    extern "rust-call" fn call(&self, _: ()) -> T {
+      match *self {
+        Foo(t) => t
+      }
+    }
+}
+
+impl<T: Copy> FnMut<()> for Foo<T> {
+    extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
+        self.call(())
+    }
+}
+
+impl<T: Copy> FnOnce<()> for Foo<T> {
+    type Output = T;
+
+    extern "rust-call" fn call_once(self, _: ()) -> T {
+        self.call(())
+    }
+}
+
+fn main() {
+  let t: u8 = 1;
+  println!("{}", Foo(t)());
+}
index d49b44c8a3586c7e677ff76e8d0f42f154d12eaa..1b93d3c96376a81161b9661d2bae1557fefb233f 100644 (file)
@@ -12,3 +12,4 @@ LL | #[unstable(feature = "foo", issue = "none")]
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0711`.
index e44a84776bc696c01511e35fccf4b8efa2b682c4..539c8fb27b3b0a5b5909b4e791da7d7f3d68bc03 100644 (file)
@@ -5,7 +5,8 @@
 
 extern crate proc_macro;
 
-use proc_macro::{Literal, Span, TokenStream, TokenTree};
+use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
 
 #[proc_macro]
 pub fn foo_with_input_span(input: TokenStream) -> TokenStream {
@@ -26,3 +27,14 @@ pub fn err_with_input_span(input: TokenStream) -> TokenStream {
 
     TokenStream::from(TokenTree::Literal(lit))
 }
+
+#[proc_macro]
+pub fn respan_to_invalid_format_literal(input: TokenStream) -> TokenStream {
+    let mut s = Literal::string("{");
+    s.set_span(input.into_iter().next().unwrap().span());
+    TokenStream::from_iter([
+        TokenTree::from(Ident::new("format", Span::call_site())),
+        TokenTree::from(Punct::new('!', Spacing::Alone)),
+        TokenTree::from(Group::new(Delimiter::Parenthesis, TokenTree::from(s).into())),
+    ])
+}
index a8a2a47fe46e1f6ed7a478b9f99d3e9d1167dddf..c2619d6df58b31d0007903e5f1cf9ad600454a78 100644 (file)
@@ -170,7 +170,7 @@ LL |     format!("foo %s baz", "bar");
    |                  |
    |                  help: format specifiers use curly braces: `{}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: invalid format string: expected `'}'`, found `'t'`
   --> $DIR/ifmt-bad-arg.rs:75:1
index 96277d4d0d9d7861d7fd4885773d1ea8da27db0e..fc99af40859215a8b86ebf8dee42a0b14ff0634a 100644 (file)
@@ -10,5 +10,5 @@ fn main() {
     //~| NOTE: argument never used
     //~| NOTE: argument never used
     //~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
-    //~| NOTE: printf formatting not supported
+    //~| NOTE: printf formatting is not supported
 }
index 7b21e0a4fc8965f22278dddfb0ed80eee150c412..ddeb769eadc525ca951ff47ac5d00b5ff6979635 100644 (file)
@@ -12,7 +12,7 @@ note: format specifiers use curly braces, and you have to use a positional or na
    |
 LL |     print!("%0*x", width, num);
    |             ^^^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/fmt/respanned-literal-issue-106191.rs b/src/test/ui/fmt/respanned-literal-issue-106191.rs
new file mode 100644 (file)
index 0000000..44642a1
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:format-string-proc-macro.rs
+
+extern crate format_string_proc_macro;
+
+fn main() {
+    format_string_proc_macro::respan_to_invalid_format_literal!("¡");
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
+    format_args!(r#concat!("¡        {"));
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
+}
diff --git a/src/test/ui/fmt/respanned-literal-issue-106191.stderr b/src/test/ui/fmt/respanned-literal-issue-106191.stderr
new file mode 100644 (file)
index 0000000..73a3af6
--- /dev/null
@@ -0,0 +1,19 @@
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/respanned-literal-issue-106191.rs:6:65
+   |
+LL |     format_string_proc_macro::respan_to_invalid_format_literal!("¡");
+   |                                                                 ^^^ expected `'}'` in format string
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/respanned-literal-issue-106191.rs:8:18
+   |
+LL |     format_args!(r#concat!("¡        {"));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
index 7c626a01b1298dfdb64655d763eb2d31ba2721a4..19bee733ec068c83be742e3d0171dd89892fd50d 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {
     let needlesArr: Vec<char> = vec!['a', 'f'];
     needlesArr.iter().fold(|x, y| {
-        //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+        //~^ ERROR this method takes 2 arguments but 1 argument was supplied
     });
 }
index 1232b83c39171af52a5702476cc7823ef1e50816..2690ad7117621a21240672c2ee21f1c32762897f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 2 arguments but 1 argument was supplied
+error[E0061]: this method takes 2 arguments but 1 argument was supplied
   --> $DIR/issue-3044.rs:3:23
    |
 LL |       needlesArr.iter().fold(|x, y| {
index fcef6f1b60ecf6864a930bcdd576bfacd70be504..35e39bebb29ab85d7d1424e4ea28c01aac7190a8 100644 (file)
@@ -18,9 +18,9 @@ fn returns_fn_ptr() -> _ {
 fn returns_closure() -> _ {
 //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
 //~| NOTE not allowed in type signatures
-//~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
-//~| NOTE for more information on `Fn` traits and closure types, see
-//        https://doc.rust-lang.org/book/ch13-01-closures.html
+//~| HELP replace with an appropriate return type
+//~| SUGGESTION impl Fn() -> i32
+//~| NOTE for more information on `Fn` traits and closure types
     || 0
 }
 
index 2ca4ae982d96f30bca872b276ae28812a37b36f7..f5d6c44db75119be1fab07c1a1f006e8b90dfcb8 100644 (file)
@@ -11,9 +11,11 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
   --> $DIR/issue-80179.rs:18:25
    |
 LL | fn returns_closure() -> _ {
-   |                         ^ not allowed in type signatures
+   |                         ^
+   |                         |
+   |                         not allowed in type signatures
+   |                         help: replace with an appropriate return type: `impl Fn() -> i32`
    |
-   = help: consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
    = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/fn/suggest-return-closure.rs b/src/test/ui/fn/suggest-return-closure.rs
new file mode 100644 (file)
index 0000000..33daa1e
--- /dev/null
@@ -0,0 +1,34 @@
+fn fn_once() -> _ {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+    //~| NOTE not allowed in type signatures
+    //~| HELP replace with an appropriate return type
+    //~| SUGGESTION impl FnOnce()
+    //~| NOTE for more information on `Fn` traits and closure types
+    let x = String::new();
+    || {
+        drop(x);
+    }
+}
+
+fn fn_mut() -> _ {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+    //~| NOTE not allowed in type signatures
+    //~| HELP replace with an appropriate return type
+    //~| SUGGESTION impl FnMut(char)
+    //~| NOTE for more information on `Fn` traits and closure types
+    let x = String::new();
+    |c| {
+        x.push(c);
+    }
+}
+
+fn fun() -> _ {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+    //~| NOTE not allowed in type signatures
+    //~| HELP replace with an appropriate return type
+    //~| SUGGESTION impl Fn() -> i32
+    //~| NOTE for more information on `Fn` traits and closure types
+    || 1i32
+}
+
+fn main() {}
diff --git a/src/test/ui/fn/suggest-return-closure.stderr b/src/test/ui/fn/suggest-return-closure.stderr
new file mode 100644 (file)
index 0000000..3410444
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/suggest-return-closure.rs:1:17
+   |
+LL | fn fn_once() -> _ {
+   |                 ^
+   |                 |
+   |                 not allowed in type signatures
+   |                 help: replace with an appropriate return type: `impl FnOnce()`
+   |
+   = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/suggest-return-closure.rs:13:16
+   |
+LL | fn fn_mut() -> _ {
+   |                ^
+   |                |
+   |                not allowed in type signatures
+   |                help: replace with an appropriate return type: `impl FnMut(char)`
+   |
+   = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/suggest-return-closure.rs:25:13
+   |
+LL | fn fun() -> _ {
+   |             ^
+   |             |
+   |             not allowed in type signatures
+   |             help: replace with an appropriate return type: `impl Fn() -> i32`
+   |
+   = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/fn/suggest-return-future.rs b/src/test/ui/fn/suggest-return-future.rs
new file mode 100644 (file)
index 0000000..750740d
--- /dev/null
@@ -0,0 +1,23 @@
+// edition: 2021
+
+async fn a() -> i32 {
+    0
+}
+
+fn foo() -> _ {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+    //~| NOTE not allowed in type signatures
+    //~| HELP replace with an appropriate return type
+    //~| SUGGESTION impl Future<Output = i32>
+    a()
+}
+
+fn bar() -> _ {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
+    //~| NOTE not allowed in type signatures
+    //~| HELP replace with an appropriate return type
+    //~| SUGGESTION impl Future<Output = i32>
+    async { a().await }
+}
+
+fn main() {}
diff --git a/src/test/ui/fn/suggest-return-future.stderr b/src/test/ui/fn/suggest-return-future.stderr
new file mode 100644 (file)
index 0000000..a4c8b5d
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/suggest-return-future.rs:7:13
+   |
+LL | fn foo() -> _ {
+   |             ^
+   |             |
+   |             not allowed in type signatures
+   |             help: replace with an appropriate return type: `impl Future<Output = i32>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/suggest-return-future.rs:15:13
+   |
+LL | fn bar() -> _ {
+   |             ^
+   |             |
+   |             not allowed in type signatures
+   |             help: replace with an appropriate return type: `impl Future<Output = i32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
index 40bf7a3898acc866f7cfc6fc29e432d6b7834adf..6f430687e6d6efd057001cb8686e328839dca7ba 100644 (file)
@@ -23,7 +23,7 @@ LL |     foo::<for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&()
    |     required by a bound introduced by this call
    |
    = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
-   = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`
+   = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn Display + 'a)`
 note: required by a bound in `foo`
   --> $DIR/unsized-ret.rs:5:11
    |
index 49a514a8b4e3461007e609d85d42a5522cdb4a81..612fe1b841918f81a5fd92b3bc512f4cecf877c2 100644 (file)
@@ -4,7 +4,6 @@
 
 trait Bar {
     //~^ NOTE `Bar` defines an item `bar`, perhaps you need to implement it
-    //~| NOTE `Bar` defines an item `bar`, perhaps you need to implement it
     fn bar(&self) {}
 }
 
@@ -15,9 +14,6 @@ fn main() {
     //~^ ERROR cannot find value `oops` in this scope
     //~| NOTE not found
     arc.bar();
-    //~^ ERROR no method named `bar`
-    //~| NOTE method not found
-    //~| HELP items from traits can only be used if the trait is implemented and in scope
 
     let arc2 = std::sync::Arc::new(|| Foo);
     arc2.bar();
index 463ac7684ecdfea3a73122953e24915249278b66..83a2b1f58f9c58ddc1305d48a213f8ca43439b98 100644 (file)
@@ -1,27 +1,14 @@
 error[E0425]: cannot find value `oops` in this scope
-  --> $DIR/fn-help-with-err.rs:14:35
+  --> $DIR/fn-help-with-err.rs:13:35
    |
 LL |     let arc = std::sync::Arc::new(oops);
    |                                   ^^^^ not found in this scope
 
-error[E0599]: no method named `bar` found for struct `Arc<_>` in the current scope
-  --> $DIR/fn-help-with-err.rs:17:9
-   |
-LL |     arc.bar();
-   |         ^^^ method not found in `Arc<_>`
-   |
-   = help: items from traits can only be used if the trait is implemented and in scope
-note: `Bar` defines an item `bar`, perhaps you need to implement it
-  --> $DIR/fn-help-with-err.rs:5:1
-   |
-LL | trait Bar {
-   | ^^^^^^^^^
-
-error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:22:36]>` in the current scope
-  --> $DIR/fn-help-with-err.rs:23:10
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:18:36]>` in the current scope
+  --> $DIR/fn-help-with-err.rs:19:10
    |
 LL |     arc2.bar();
-   |          ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:22:36]>`
+   |          ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:18:36]>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `bar`, perhaps you need to implement it
@@ -34,7 +21,7 @@ help: use parentheses to call this closure
 LL |     arc2().bar();
    |         ++
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0425, E0599.
 For more information about an error, try `rustc --explain E0425`.
index 0589c5a009a1b1e2ce12fb3597fc2f38a6e8651e..35acd5cd727c2713b2d6e8e4088d50418fa363f4 100644 (file)
@@ -14,7 +14,7 @@ fn main() {
         a = d;
     };
     Pin::new(&mut b).resume();
-    //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+    //~^ ERROR this method takes 1 argument but 0 arguments were supplied
     // This type error is required to reproduce the ICE...
 }
 
index afb39c9e594d17887c8890ca793d7dcad17a3df0..f6d2440295e8d3c691ef499e93884a29e1403a36 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
   --> $DIR/issue-102645.rs:16:22
    |
 LL |     Pin::new(&mut b).resume();
index ed0628bbbc3cce135ed9308d8911b9aa66e14fff..ebf35be581c60a1c3478ee964f57a1badb32dad1 100644 (file)
@@ -35,7 +35,7 @@ note: required because it's used within this generator
    |
 LL |     || {
    |     ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
   --> $DIR/generator-print-verbose-1.rs:41:30
    |
 LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
index a9996123f23437a6d3da97441051332a44836bcd..842b23bd49dd3b5d8b4aeec0a889ecd2970780e5 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Assoc<'a> where Self: 'a;
 help: add missing lifetime argument
    |
 LL |     fn g(&self) -> Self::Assoc<'_>;
-   |                          ~~~~~~~~~
+   |                               ++++
 
 error[E0107]: missing generics for associated type `Trait::Assoc`
   --> $DIR/elided-in-expr-position.rs:31:26
@@ -28,7 +28,7 @@ LL |     type Assoc<'a> where Self: 'a;
 help: add missing lifetime argument
    |
 LL |     fn g(&self) -> Self::Assoc<'_> {
-   |                          ~~~~~~~~~
+   |                               ++++
 
 error: aborting due to 2 previous errors
 
index 452dfefd1e3d5ac3b6d90d0cbce2e4e3a2b47e36..499221637ba7f01e3c5d60429a20c7e60d7f1ab6 100644 (file)
@@ -12,7 +12,7 @@ LL |   type Y<'a>;
 help: add missing lifetime argument
    |
 LL |   fn foo<'a, T1: X<Y<'a> = T1>>(t : T1) -> T1::Y<'a> {
-   |                    ~~~~~
+   |                     ++++
 
 error[E0107]: missing generics for associated type `X::Y`
   --> $DIR/gat-trait-path-missing-lifetime.rs:8:20
@@ -28,7 +28,7 @@ LL |   type Y<'a>;
 help: add missing lifetime argument
    |
 LL |   fn foo<'a, T1: X<Y<'a> = T1>>(t : T1) -> T1::Y<'a> {
-   |                    ~~~~~
+   |                     ++++
 
 error: aborting due to 2 previous errors
 
index 01165fcebaf778c1b82813a6cda1f62eb130c07c..e45bdcf92134045484115081675c18d934f2e911 100644 (file)
@@ -15,7 +15,6 @@ impl<T> Foo for Fooy<T> {
     //~^ ERROR impl has stricter requirements than trait
     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
     //~^ ERROR impl has stricter requirements than trait
-    //~| ERROR lifetime bound not satisfied
     type C = String where Self: Copy;
     //~^ ERROR the trait bound `T: Copy` is not satisfied
     fn d() where Self: Copy {}
index 442d4f33690ebd793e8b1aba86224b9a53dd1b08..3456b345cc28c04c329be128cc5b6d40c6d5a5b4 100644 (file)
@@ -15,29 +15,14 @@ LL |     type B<'a, 'b> where 'a: 'b;
 ...
 LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
    |                                                ^^ impl has extra requirement `'b: 'a`
-
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/impl_bounds.rs:16:22
    |
-LL |     type B<'a, 'b> where 'a: 'b;
-   |     -------------- definition of `B` from trait
-...
-LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
-   |                      ^^^^^^^^^^^^^^^             - help: try copying this clause from the trait: `, 'a: 'b`
+help: copy the `where` clause predicates from the trait
    |
-note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/impl_bounds.rs:16:12
-   |
-LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
-   |            ^^
-note: but lifetime parameter must outlive the lifetime `'b` as defined here
-  --> $DIR/impl_bounds.rs:16:16
-   |
-LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
-   |                ^^
+LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'a: 'b;
+   |                                      ~~~~~~~~~~~~
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/impl_bounds.rs:19:33
+  --> $DIR/impl_bounds.rs:18:33
    |
 LL |     type C = String where Self: Copy;
    |                                 ^^^^ the trait `Copy` is not implemented for `T`
@@ -62,7 +47,7 @@ LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/impl_bounds.rs:21:24
+  --> $DIR/impl_bounds.rs:20:24
    |
 LL |     fn d() where Self: Copy {}
    |                        ^^^^ the trait `Copy` is not implemented for `T`
@@ -86,7 +71,7 @@ help: consider restricting type parameter `T`
 LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
    |       +++++++++++++++++++
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0276, E0277, E0478.
+Some errors have detailed explanations: E0276, E0277.
 For more information about an error, try `rustc --explain E0276`.
index 386c97161c8f1d01fc5ac40ec9f253036f699161..4b4fe43e8c4fd523a6caf74d37abfaae189a1a3e 100644 (file)
@@ -12,7 +12,7 @@ LL |     type A<'a>;
 help: add missing lifetime argument
    |
 LL |   inner: Box<dyn Provider<A<'a> = B>>,
-   |                           ~~~~~
+   |                            ++++
 
 error: aborting due to previous error
 
index 088f69b09f704406a1574f8207a5f5fa8e89dcd0..52c6e3eec6039379f378fa5725f73162c8c6130f 100644 (file)
@@ -12,7 +12,7 @@ LL |     type SubType<'a>: SubTrait where Self: 'a;
 help: add missing lifetime argument
    |
 LL |     let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
-   |                                 ~~~~~~~~~~~
+   |                                        ++++
 
 error[E0038]: the trait `SuperTrait` cannot be made into an object
   --> $DIR/issue-76535.rs:39:14
index e79f0a73f5b5058dac8edab64c56801b1f1e0826..369b86d29284d7c8b682961750e9f3070a8c2447 100644 (file)
@@ -12,7 +12,7 @@ LL |     type SubType<'a>: SubTrait where Self: 'a;
 help: add missing lifetime argument
    |
 LL |     let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0));
-   |                                 ~~~~~~~~~~~
+   |                                        ++++
 
 error: aborting due to previous error
 
index 514f8d45a15f4cfe8dbe86a1d553bb84eebf8367..bad8c1c9dba7b40c14f36b740be5ca2fce766d31 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Member<T>;
 help: add missing generic argument
    |
 LL |     Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
-   |                                               ~~~~~~~~~
+   |                                                     +++
 
 error[E0038]: the trait `CollectionFamily` cannot be made into an object
   --> $DIR/issue-78671.rs:10:25
index 6fa09a4c7e596824004f5a3c787efdc49b90f4ea..1d8a3d410f8dc0d971f8902f3c21d764e2949ffe 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Member<T>;
 help: add missing generic argument
    |
 LL |     Box::new(Family) as &dyn CollectionFamily<Member<T>=usize>
-   |                                               ~~~~~~~~~
+   |                                                     +++
 
 error: aborting due to previous error
 
index 3c1a29d48b2fe85ac8216a1704c7051d7578f3ee..f1de77bc3c0ab2045bd2fd7f663389ab022b3f08 100644 (file)
@@ -12,7 +12,7 @@ LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
 help: add missing lifetime argument
    |
 LL |         as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
-   |                                    ~~~~~~~~~~~~
+   |                                            ++++
 
 error[E0038]: the trait `MapLike` cannot be made into an object
   --> $DIR/issue-79422.rs:47:12
index 58c921bf09f6da563fa1736a6e0ce48d0338f51c..d79de0ca62792cbffd112b529c527b094aaac760 100644 (file)
@@ -12,7 +12,7 @@ LL |     type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
 help: add missing lifetime argument
    |
 LL |         as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>;
-   |                                    ~~~~~~~~~~~~
+   |                                            ++++
 
 error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'_> == (dyn RefCont<'_, u8> + 'static)`
   --> $DIR/issue-79422.rs:44:13
index 155477048cad9cc06e5ff8cb9e54770c74c977b6..6e0d2ff4ded410dbec1db63e59320b960db0b91e 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Wrapped<B>;
 help: add missing generic argument
    |
 LL |     MInner: Monad<Unwrapped = A, Wrapped<B> = MOuter::Wrapped<A>>,
-   |                                  ~~~~~~~~~~
+   |                                         +++
 
 error: aborting due to previous error
 
index 6a36bfc37f247287773f25cb207727ba2df21e7a..16287323995de2a6bdcf8ff7368dbc7d14482239 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Wrapped<A>: SomeTrait;
 help: add missing generic argument
    |
 LL |     W: SomeTrait<Wrapped<A> = W>,
-   |                  ~~~~~~~~~~
+   |                         +++
 
 error: aborting due to previous error
 
index 20a407dd4125ec915b738c9e14d180f6146e0d2f..4f4f96a4b9218dcc14bd009adbda44c4fe39a5e5 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Output<'a>;
 help: add missing lifetime argument
    |
 LL | fn test_simpler<'a>(dst: &'a mut impl TestMut<Output<'a> = &'a mut f32>)
-   |                                               ~~~~~~~~~~
+   |                                                     ++++
 
 error: aborting due to previous error
 
index c8961e28ede4537b6b5ef989fec9d5dac83d60e4..e0fc225f463aeed5609e35884edf2f3ffdecc43a 100644 (file)
@@ -12,7 +12,7 @@ LL |     type DType<T>: D<T, CType = Self>;
 help: add missing generic argument
    |
 LL |     type CType: C<DType<T> = Self>;
-   |                   ~~~~~~~~
+   |                        +++
 
 error: aborting due to previous error
 
index 9e21c567c73c52798a8442e35e4c4f4adac32937..df30be65ec54b676a1a70282bf3c170cccf422de 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Item<'a>;
 help: add missing lifetime argument
    |
 LL |     fn next(&mut self) -> Option<Self::Item<'_>>;
-   |                                        ~~~~~~~~
+   |                                            ++++
 
 error: aborting due to previous error
 
index 2d3f4a6af7e0b9a4e02590c7468002a3ebb9c6b8..b4b1bc7da7f455056c3809bb260ef41bb2e0e8f1 100644 (file)
@@ -5,13 +5,17 @@ LL |     type Fut<'a> where Self: 'a;
    |     ------------ definition of `Fut` from trait
 ...
 LL |     type Fut<'a> = impl Future<Output = ()>;
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: type must outlive the lifetime `'a` as defined here
   --> $DIR/issue-90014.rs:13:14
    |
 LL |     type Fut<'a> = impl Future<Output = ()>;
    |              ^^
+help: copy the `where` clause predicates from the trait
+   |
+LL |     type Fut<'a> = impl Future<Output = ()> where Self: 'a;
+   |                                             ++++++++++++++
 
 error: aborting due to previous error
 
index e321da53d5668bd61237ae89c268518b023ef549..adc0cb4e0423f2e5db414a7a649e0eea3c3e95d5 100644 (file)
@@ -14,14 +14,6 @@ fn foo<T>() {
     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
     //~^ ERROR `T` does not live long enough
     //~| ERROR `T` does not live long enough
-    //~| ERROR `T` does not live long enough
-    //~| ERROR `T` does not live long enough
-    //~| ERROR `T` does not live long enough
-    //~| ERROR `T` does not live long enough
-    //~| ERROR `T` does not live long enough
-    //~| ERROR `T` does not live long enough
-    //~| ERROR `T` may not live long enough
-    //~| ERROR `T` may not live long enough
     //
     // FIXME: This error is bogus, but it arises because we try to validate
     // that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
index 5485570cecd76eb0d1c245163c250b07ad3729fa..d9d76adfbb55280b154fd576501b4b9fccc7f96a 100644 (file)
@@ -10,64 +10,5 @@ error: `T` does not live long enough
 LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `T` does not live long enough
-  --> $DIR/issue-91139.rs:14:12
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `T` does not live long enough
-  --> $DIR/issue-91139.rs:14:12
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/issue-91139.rs:14:58
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |                                                          ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | fn foo<T: 'static>() {
-   |         +++++++++
-
-error: `T` does not live long enough
-  --> $DIR/issue-91139.rs:14:58
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |                                                          ^^^^^^^^^
-
-error: `T` does not live long enough
-  --> $DIR/issue-91139.rs:14:58
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |                                                          ^^^^^^^^^
-
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/issue-91139.rs:14:58
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |                                                          ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | fn foo<T: 'static>() {
-   |         +++++++++
-
-error: `T` does not live long enough
-  --> $DIR/issue-91139.rs:14:58
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |                                                          ^^^^^^^^^
-
-error: `T` does not live long enough
-  --> $DIR/issue-91139.rs:14:58
-   |
-LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
-   |                                                          ^^^^^^^^^
-
-error: aborting due to 10 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0310`.
index 1cfc2aaf1613ffabf414ec4ee93c5014658b13c6..d5db962094ce99f67ef6b80fa97d1e373f701c7c 100644 (file)
@@ -5,7 +5,7 @@ LL |     type Cursor<'tx>: Cursor<'tx>
    |     ----------------------------- definition of `Cursor` from trait
 ...
 LL |     type Cursor<'tx> = CursorImpl<'tx>;
-   |                        ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx`
+   |                        ^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'db` as defined here
   --> $DIR/issue-91883.rs:29:6
@@ -17,6 +17,10 @@ note: but lifetime parameter must outlive the lifetime `'tx` as defined here
    |
 LL |     type Cursor<'tx> = CursorImpl<'tx>;
    |                 ^^^
+help: copy the `where` clause predicates from the trait
+   |
+LL |     type Cursor<'tx> = CursorImpl<'tx> where 'db: 'tx, Self: 'tx;
+   |                                        +++++++++++++++++++++++++
 
 error: aborting due to previous error
 
index cd7eed25421e8bab1a0caa03f0054ae3409c41b1..ddc420a7b4e610eed042330682d4c2f6117e1bc0 100644 (file)
@@ -5,13 +5,17 @@ LL |     type TextureIter<'a>: Iterator<Item = &'a Texture>
    |     -------------------------------------------------- definition of `TextureIter` from trait
 ...
 LL |     type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: type must outlive the lifetime `'a` as defined here
   --> $DIR/issue-92033.rs:20:22
    |
 LL |     type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
    |                      ^^
+help: copy the `where` clause predicates from the trait
+   |
+LL |     type TextureIter<'a> = std::option::IntoIter<&'a Texture> where Self: 'a;
+   |                                                               ++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/mismatched-where-clause-regions.rs b/src/test/ui/generic-associated-types/mismatched-where-clause-regions.rs
new file mode 100644 (file)
index 0000000..8caf531
--- /dev/null
@@ -0,0 +1,12 @@
+trait Foo {
+    type T<'a1, 'b1>
+    where
+        'a1: 'b1;
+}
+
+impl Foo for () {
+    type T<'a2, 'b2> = () where 'b2: 'a2;
+    //~^ ERROR impl has stricter requirements than trait
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/mismatched-where-clause-regions.stderr b/src/test/ui/generic-associated-types/mismatched-where-clause-regions.stderr
new file mode 100644 (file)
index 0000000..91a0300
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/mismatched-where-clause-regions.rs:8:38
+   |
+LL |     type T<'a1, 'b1>
+   |     ---------------- definition of `T` from trait
+...
+LL |     type T<'a2, 'b2> = () where 'b2: 'a2;
+   |                                      ^^^ impl has extra requirement `'b2: 'a2`
+   |
+help: copy the `where` clause predicates from the trait
+   |
+LL |     type T<'a2, 'b2> = () where 'a2: 'b2;
+   |                           ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0276`.
index ffdba6676bf8dd38f84cce2b39823fef51e5cfbb..8a71fc73a9d2d3fa82d6a68ad206d2e3d06c6f3b 100644 (file)
@@ -6,6 +6,12 @@ LL |     type Assoc<'a, 'b>;
 ...
 LL |     type Assoc<'a, 'b> = () where 'a: 'b;
    |                                       ^^ impl has extra requirement `'a: 'b`
+   |
+help: remove the `where` clause
+   |
+LL -     type Assoc<'a, 'b> = () where 'a: 'b;
+LL +     type Assoc<'a, 'b> = () ;
+   |
 
 error: aborting due to previous error
 
index 752587c25a7335b589adbbae711671a9199f942f..8f74b12c008e66785c95cd4f6d24e99bbf4343c8 100644 (file)
@@ -12,7 +12,7 @@ LL |     type Y<'a, 'b>;
 help: add missing lifetime arguments
    |
 LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'_, '_> = (&'c u32, &'d u32)>>) {}
-   |                                ~~~~~~~~~
+   |                                 ++++++++
 
 error[E0107]: this struct takes 3 lifetime arguments but 2 lifetime arguments were supplied
   --> $DIR/missing_lifetime_args.rs:14:26
index e45a0d9ca77377008377824823a370d8c7d909fe..6450bbd8b43260993f059cb427c0b9dc4cf0a91e 100644 (file)
@@ -12,7 +12,7 @@ LL | struct Vec<T, A = Heap>(
 help: add missing generic argument
    |
 LL |     let _: Vec<T>;
-   |            ~~~~~~
+   |               +++
 
 error: aborting due to previous error
 
index e45387acaf31df709d6c0860898fce2d5e021d6f..9d859fddf56b472d706ab7e0529647bdfbdc238d 100644 (file)
@@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
    |
 LL | fn should_error<T>() where T : Into<&u32> {}
    |                                     ^ explicit lifetime name needed here
+   |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:32
+   |
+LL | fn should_error<T>() where T : Into<&u32> {}
+   |                                ^
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20
index b48966a1a1ed0c66f351b39ab7e7b8c5de8ddd8e..75e33f680eadb4ea4767d85e0a15c25e2fb643ff 100644 (file)
@@ -251,7 +251,7 @@ LL |     struct Ty<A, B>;
 help: add missing generic arguments
    |
 LL |     type A = Ty<A, B>;
-   |              ~~~~~~~~
+   |                ++++++
 
 error[E0107]: this struct takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:30:14
@@ -315,7 +315,7 @@ LL |     struct Ty<'a, T>;
 help: add missing generic argument
    |
 LL |     type A = Ty<T>;
-   |              ~~~~~
+   |                +++
 
 error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:54:14
@@ -391,7 +391,7 @@ LL |     struct Ty<A, B, C = &'static str>;
 help: add missing generic arguments
    |
 LL |     type A = Ty<A, B>;
-   |              ~~~~~~~~
+   |                ++++++
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:84:14
@@ -483,7 +483,7 @@ LL |     trait GenericType<A> {
 help: add missing generic argument
    |
 LL |     type D = Box<dyn GenericType<A>>;
-   |                      ~~~~~~~~~~~~~~
+   |                                 +++
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:133:22
@@ -892,7 +892,7 @@ LL |         type A = HashMap;
 help: add missing generic arguments
    |
 LL |         type A = HashMap<K, V>;
-   |                  ~~~~~~~~~~~~~
+   |                         ++++++
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:314:18
@@ -954,7 +954,7 @@ LL |         type A = Result;
 help: add missing generic arguments
    |
 LL |         type A = Result<T, E>;
-   |                  ~~~~~~~~~~~~
+   |                        ++++++
 
 error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:338:18
diff --git a/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs
new file mode 100644 (file)
index 0000000..4b096be
--- /dev/null
@@ -0,0 +1,20 @@
+// Test that Fn-family traits with lifetime parameters shouldn't compile and
+// we suggest the usage of higher-rank trait bounds instead.
+
+fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+use std::ops::Fn as AliasedFn;
+fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr
new file mode 100644 (file)
index 0000000..e8f6d63
--- /dev/null
@@ -0,0 +1,62 @@
+error: `Fn` traits cannot take lifetime parameters
+  --> $DIR/hrtb-malformed-lifetime-generics.rs:4:17
+   |
+LL | fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+   |                 ^^^^
+   |
+help: consider using a higher-ranked trait bound instead
+   |
+LL - fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+LL + fn fa(_: impl for<'a> Fn(&'a str) -> bool) {}
+   |
+
+error: `Fn` traits cannot take lifetime parameters
+  --> $DIR/hrtb-malformed-lifetime-generics.rs:7:20
+   |
+LL | fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+   |                    ^^^^^^^^
+   |
+help: consider using a higher-ranked trait bound instead
+   |
+LL - fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+LL + fn fb(_: impl for<'a, 'b> FnMut(&'a str, &'b str) -> bool) {}
+   |
+
+error: `Fn` traits cannot take lifetime parameters
+  --> $DIR/hrtb-malformed-lifetime-generics.rs:10:41
+   |
+LL | fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+   |                                         ^^^^
+   |
+help: consider using a higher-ranked trait bound instead
+   |
+LL - fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+LL + fn fc(_: impl std::fmt::Display + for<'a> FnOnce(&'a str) -> bool + std::fmt::Debug) {}
+   |
+
+error: `Fn` traits cannot take lifetime parameters
+  --> $DIR/hrtb-malformed-lifetime-generics.rs:14:24
+   |
+LL | fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+   |                        ^^^^
+   |
+help: consider using a higher-ranked trait bound instead
+   |
+LL - fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+LL + fn fd(_: impl for<'a> AliasedFn(&'a str) -> bool) {}
+   |
+
+error: `Fn` traits cannot take lifetime parameters
+  --> $DIR/hrtb-malformed-lifetime-generics.rs:17:27
+   |
+LL | fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+   |                           ^^^^
+   |
+help: consider using a higher-ranked trait bound instead
+   |
+LL - fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+LL + fn fe<F>(_: F) where F: for<'a> Fn(&'a str) -> bool {}
+   |
+
+error: aborting due to 5 previous errors
+
index f36d549e476b8baa6b04d25125475c8dd3284965..6006a108c5cc6e3adc7c69ea31e6aa1970d4dfa8 100644 (file)
@@ -9,5 +9,5 @@ fn f<I>(i: I)
 {}
 
 fn main() {
-    f(&[f()]); //~ ERROR this function takes 1 argument
+    f(&[f()]); //~ ERROR function takes 1 argument
 }
index c10a0888a4f2746e7a2cb15677629ca87c46a5fc..8aa29926d4f9b2b15ca0f6dbdecdb7dd6b989b42 100644 (file)
@@ -7,6 +7,7 @@ trait SomeTrait<'a> {
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
     //~^ ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
+    //~| ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
index 25a4f6088deba56f0a34782cd779bf5a8efbd32c..3240518fbbe0808447ca8fe4f15ed5fca7e24efa 100644 (file)
@@ -1,3 +1,14 @@
+error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
+  --> $DIR/issue-85455.rs:8:14
+   |
+LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
+   |                 +++++++++++++++++++++++
+
 error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
   --> $DIR/issue-85455.rs:8:5
    |
@@ -9,6 +20,6 @@ help: consider restricting type parameter `T`
 LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
    |                 +++++++++++++++++++++++
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed b/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed
new file mode 100644 (file)
index 0000000..74f3c88
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+     *t.min().unwrap() //~ ERROR the `min` method cannot be invoked on
+}
+
+fn main() {
+     let array = [0u64];
+     test(&mut array.iter());
+}
diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs b/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs
new file mode 100644 (file)
index 0000000..3b02c5a
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
+     *t.min().unwrap() //~ ERROR the `min` method cannot be invoked on
+}
+
+fn main() {
+     let array = [0u64];
+     test(&mut array.iter());
+}
diff --git a/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr b/src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr
new file mode 100644 (file)
index 0000000..89613bd
--- /dev/null
@@ -0,0 +1,13 @@
+error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
+  --> $DIR/mutability-mismatch-arg.rs:3:9
+   |
+LL |      *t.min().unwrap()
+   |         ^^^
+   |
+help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+   |
+LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+   |             +++
+
+error: aborting due to previous error
+
index deb84f6fe97cfd5d4d2560ec586c2d16f772847b..01bb3537c2ddc7449e1e2788bf995b39848cec07 100644 (file)
@@ -4,7 +4,6 @@ pub trait MutTrait {
     fn function(&mut self)
     where
         Self: Sized;
-    //~^ this has a `Sized` requirement
 }
 
 impl MutTrait for MutType {
@@ -17,7 +16,6 @@ pub trait Trait {
     fn function(&self)
     where
         Self: Sized;
-    //~^ this has a `Sized` requirement
 }
 
 impl Trait for Type {
@@ -26,9 +24,9 @@ fn function(&self) {}
 
 fn main() {
     (&MutType as &dyn MutTrait).function();
-    //~^ ERROR the `function` method cannot be invoked on a trait object
-    //~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+    //~^ ERROR the `function` method cannot be invoked on `&dyn MutTrait`
+    //~| HELP you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
     (&mut Type as &mut dyn Trait).function();
-    //~^ ERROR the `function` method cannot be invoked on a trait object
-    //~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
+    //~^ ERROR the `function` method cannot be invoked on `&mut dyn Trait`
+    //~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
 }
index dbbf79a4f1a034f08b771dc12e1af7b34e0b7532..2ca571d9b7926d7b4c65341d4d562e982a5ff617 100644 (file)
@@ -1,24 +1,18 @@
-error: the `function` method cannot be invoked on a trait object
-  --> $DIR/mutability-mismatch.rs:28:33
+error: the `function` method cannot be invoked on `&dyn MutTrait`
+  --> $DIR/mutability-mismatch.rs:26:33
    |
-LL |         Self: Sized;
-   |               ----- this has a `Sized` requirement
-...
 LL |     (&MutType as &dyn MutTrait).function();
    |                                 ^^^^^^^^
    |
-   = note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+   = help: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
 
-error: the `function` method cannot be invoked on a trait object
-  --> $DIR/mutability-mismatch.rs:31:35
+error: the `function` method cannot be invoked on `&mut dyn Trait`
+  --> $DIR/mutability-mismatch.rs:29:35
    |
-LL |         Self: Sized;
-   |               ----- this has a `Sized` requirement
-...
 LL |     (&mut Type as &mut dyn Trait).function();
    |                                   ^^^^^^^^
    |
-   = note: you need `&dyn Trait` instead of `&mut dyn Trait`
+   = help: you need `&dyn Trait` instead of `&mut dyn Trait`
 
 error: aborting due to 2 previous errors
 
index 7249a36f5fe7b7b4de607b3d118cc0d52c849469..a93bdb1788f94af05e203fd97dd805e8729defcc 100644 (file)
@@ -2,5 +2,5 @@ fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {}
 
 fn main() {
     f::<[u8]>("a", b"a");
-    //~^ ERROR: this function takes 2 generic arguments but 1 generic argument was supplied
+    //~^ ERROR function takes 2 generic arguments but 1 generic argument was supplied
 }
index acf768d5795e5311a5526cd1e3639cb00601ccde..db97fc2bdc46a8483c7b5005111ccef459d70f70 100644 (file)
@@ -13,8 +13,8 @@ note: type in trait
    |
 LL |     fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
    |                                ^^
-   = note: expected fn pointer `fn(&(), &B, &impl Debug)`
-              found fn pointer `fn(&(), &impl Debug, &B)`
+   = note: expected signature `fn(&(), &B, &impl Debug)`
+              found signature `fn(&(), &impl Debug, &B)`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
diff --git a/src/test/ui/impl-trait/in-trait/box-coerce-span-in-default.rs b/src/test/ui/impl-trait/in-trait/box-coerce-span-in-default.rs
new file mode 100644 (file)
index 0000000..a4d483d
--- /dev/null
@@ -0,0 +1,49 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
+
+struct TestA {}
+struct TestB {}
+
+impl TestTrait for TestA {
+    type Output = ();
+}
+impl TestTrait for TestB {
+    type Output = ();
+}
+
+trait TestTrait {
+    type Output;
+}
+
+impl<A, B> TestTrait for GreeterOutput<A, B>
+where
+    A: TestTrait<Output = ()>,
+    B: TestTrait<Output = ()>,
+{
+    type Output = ();
+}
+
+enum GreeterOutput<A, B>
+where
+    A: TestTrait<Output = ()>,
+    B: TestTrait<Output = ()>,
+{
+    SayHello(A),
+    SayGoodbye(B),
+}
+
+trait Greeter {
+    fn test_func(&self, func: &str) -> impl TestTrait<Output = ()> {
+        match func {
+            "SayHello" => GreeterOutput::SayHello(TestA {}),
+            "SayGoodbye" => GreeterOutput::SayGoodbye(TestB {}),
+            _ => GreeterOutput::SayHello(TestA {}),
+        }
+    }
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr b/src/test/ui/impl-trait/in-trait/box-coerce-span-in-default.stderr
new file mode 100644 (file)
index 0000000..d681ecf
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/box-coerce-span-in-default.rs:3:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
index 2b32c52c829ec4075449fb3d2ee77f86e0b304af..4dfd772222e5de25f627958cea5d245549adff35 100644 (file)
@@ -12,8 +12,8 @@ note: type in trait
    |
 LL |     fn owo(x: ()) -> impl Sized;
    |               ^^
-   = note: expected fn pointer `fn(())`
-              found fn pointer `fn(u8)`
+   = note: expected signature `fn(())`
+              found signature `fn(u8)`
 
 error[E0053]: method `owo` has an incompatible type for trait
   --> $DIR/method-signature-matches.rs:20:21
@@ -39,8 +39,8 @@ note: type in trait
    |
 LL |     async fn owo(x: ()) {}
    |                     ^^
-   = note: expected fn pointer `fn(()) -> _`
-              found fn pointer `fn(u8) -> _`
+   = note: expected signature `fn(()) -> _`
+              found signature `fn(u8) -> _`
 
 error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
   --> $DIR/method-signature-matches.rs:29:28
@@ -75,8 +75,8 @@ note: type in trait
    |
 LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
    |                            ^^^^^^^^^
-   = note: expected fn pointer `fn(&'early T)`
-              found fn pointer `fn(&())`
+   = note: expected signature `fn(&'early T)`
+              found signature `fn(&())`
 
 error: aborting due to 5 previous errors
 
index 6663d7faa1e578ebf20f97c2a3cf30bbeed43093..e105660173b48ae3af6e06e964dfd061f770ace9 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
 LL |     fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
    |
-   = note: expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static`
-              found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
+   = note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static`
+              found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index a30e6346b292714d4235c666ffd142a56d57c28e..37cfd74498d81a97a92ee2108d796432d418a753 100644 (file)
@@ -15,8 +15,8 @@ note: type in trait
    |
 LL |     fn bar(&self) -> impl Sized;
    |                      ^^^^^^^^^^
-   = note: expected fn pointer `fn(&U) -> impl Sized`
-              found fn pointer `fn(&U) -> U`
+   = note: expected signature `fn(&U) -> impl Sized`
+              found signature `fn(&U) -> U`
 
 error: aborting due to previous error
 
index be9c643b2d881c88d188cca56a8a784f499b5dae..63f4898f4306b354aa3dfa0dc849311c4dda9b3d 100644 (file)
@@ -5,7 +5,6 @@ pub struct Lint {}
 impl Lint {}
 
 pub fn gather_all() -> impl Iterator<Item = Lint> {
-    //~^ ERROR type annotations needed
     lint_files().flat_map(|f| gather_from_file(&f))
 }
 
index fc7200c75c2260d2a419bdff3ca13a7189677193..0e86561aa27798f341d2be350e965f2f849fed04 100644 (file)
@@ -1,22 +1,15 @@
 error[E0433]: failed to resolve: use of undeclared crate or module `foo`
-  --> $DIR/issue-72911.rs:12:33
+  --> $DIR/issue-72911.rs:11:33
    |
 LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
    |                                 ^^^ use of undeclared crate or module `foo`
 
 error[E0433]: failed to resolve: use of undeclared crate or module `foo`
-  --> $DIR/issue-72911.rs:17:41
+  --> $DIR/issue-72911.rs:16:41
    |
 LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
    |                                         ^^^ use of undeclared crate or module `foo`
 
-error[E0282]: type annotations needed
-  --> $DIR/issue-72911.rs:7:24
-   |
-LL | pub fn gather_all() -> impl Iterator<Item = Lint> {
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0433.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0433`.
index f09c14d3df1df216b7a01e75be34e8ab972b70ca..86d7184da7a4511a65b05bd4ef34e3127c550a51 100644 (file)
@@ -7,7 +7,7 @@ LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
 help: add missing generic argument
    |
 LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
-   |                                             ~~~~~~
+   |                                                +++
 
 error: aborting due to previous error
 
index 3ee26f74a787be7424d2f48ad65f0be1e8fb4260..c7c6ca4401266c57ba9f3c613c7dcacc482c2917 100644 (file)
@@ -18,8 +18,8 @@ LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
    |                              expected struct `Bar`, found opaque type
    |                              help: change the parameter type to match the trait: `&(a::Bar, i32)`
    |
-   = note: expected fn pointer `fn(&a::Bar, &(a::Bar, i32)) -> _`
-              found fn pointer `fn(&a::Bar, &(a::Foo, i32)) -> _`
+   = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _`
+              found signature `fn(&a::Bar, &(a::Foo, i32)) -> _`
 
 error: unconstrained opaque type
   --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16
@@ -41,8 +41,8 @@ LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
    |                              expected opaque type, found struct `Bar`
    |                              help: change the parameter type to match the trait: `&(b::Foo, i32)`
    |
-   = note: expected fn pointer `fn(&b::Bar, &(b::Foo, i32)) -> _`
-              found fn pointer `fn(&b::Bar, &(b::Bar, i32)) -> _`
+   = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _`
+              found signature `fn(&b::Bar, &(b::Bar, i32)) -> _`
 
 error: aborting due to 4 previous errors
 
index f940c1949d0b8345be0c2102b0702330e97bae2d..36ef9ea4443456916ed51322da2a7cfd97299f3a 100644 (file)
@@ -6,12 +6,10 @@ impl A {
     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
         self.x.iter().map(|a| a.0)
         //~^ ERROR: captures lifetime that does not appear in bounds
-        //~| ERROR: captures lifetime that does not appear in bounds
     }
     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
         self.x.iter().map(|a| a.0)
         //~^ ERROR: captures lifetime that does not appear in bounds
-        //~| ERROR: captures lifetime that does not appear in bounds
     }
 }
 
index b365bd8845480ca89abf64df1e5a1502f53c38ac..c451f8e37c4ec03aebd7ef0a3ab87af40bc96a4b 100644 (file)
@@ -12,36 +12,10 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
 
 error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:7:9
-   |
-LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here
-LL |         self.x.iter().map(|a| a.0)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: to declare that `impl Iterator<Item = u32>` captures `'_`, you can add an explicit `'_` lifetime bound
-   |
-LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
-   |                                                           ++++
-
-error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:12:9
-   |
-LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here
-LL |         self.x.iter().map(|a| a.0)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an explicit `'a` lifetime bound
-   |
-LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
-   |                                                             ++++
-
-error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
-  --> $DIR/static-return-lifetime-infered.rs:12:9
+  --> $DIR/static-return-lifetime-infered.rs:11:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here
+   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -50,6 +24,6 @@ help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0700`.
index bea24339837a2414cb7ecf02ac6648b287b3a871..81e4c933e53f42261257aa8ad76d53b722f2a292 100644 (file)
@@ -7,8 +7,8 @@ LL |    fn fmt(&self, x: &str) -> () { }
    |                     types differ in mutability
    |                     help: change the parameter type to match the trait: `&mut Formatter<'_>`
    |
-   = note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
-              found fn pointer `fn(&MyType, &str)`
+   = note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
+              found signature `fn(&MyType, &str)`
 
 error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2
   --> $DIR/trait_type.rs:12:11
index 79844dcbdacfd78aeca94de81b46ea5654dc58b6..c177655c5acf549cae437f52356d139ba452c7c2 100644 (file)
@@ -1,5 +1,5 @@
 // A test exploiting the bug behind #25860 except with
-// implied trait bounds which currently don't exist without `-Zchalk`.
+// implied trait bounds which currently don't exist without `-Ztrait-solver=chalk`.
 use std::marker::PhantomData;
 struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
 where
diff --git a/src/test/ui/issues/issue-105330.rs b/src/test/ui/issues/issue-105330.rs
deleted file mode 100644 (file)
index 86e45f1..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-pub trait TraitWAssocConst {
-    const A:   usize;
-}
-pub struct Demo {}
-
-impl TraitWAssocConst for impl Demo { //~ ERROR E0404
-    //~^ ERROR E0562
-    pubconst A: str = 32; //~ ERROR expected one of
-}
-
-fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
-    foo::<Demo>()(); //~ ERROR E0271
-    //~^ ERROR E0618
-    //~| ERROR E0277
-}
-
-fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
-    //~^ ERROR E0658
-    foo::<Demo>(); //~ ERROR E0277
-    //~^ ERROR E0271
-}
diff --git a/src/test/ui/issues/issue-105330.stderr b/src/test/ui/issues/issue-105330.stderr
deleted file mode 100644 (file)
index 30c3801..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-error: expected one of `!` or `::`, found `A`
-  --> $DIR/issue-105330.rs:8:14
-   |
-LL | impl TraitWAssocConst for impl Demo {
-   |                                     - while parsing this item list starting here
-LL |
-LL |     pubconst A: str = 32;
-   |              ^ expected one of `!` or `::`
-LL | }
-   | - the item list ends here
-
-error[E0404]: expected trait, found struct `Demo`
-  --> $DIR/issue-105330.rs:6:32
-   |
-LL | impl TraitWAssocConst for impl Demo {
-   |                                ^^^^ not a trait
-
-error[E0658]: associated const equality is incomplete
-  --> $DIR/issue-105330.rs:11:28
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |                            ^^^^
-   |
-   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
-   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
-
-error[E0658]: associated const equality is incomplete
-  --> $DIR/issue-105330.rs:17:29
-   |
-LL | fn main<A: TraitWAssocConst<A=32>>() {
-   |                             ^^^^
-   |
-   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
-   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
-
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
-  --> $DIR/issue-105330.rs:6:27
-   |
-LL | impl TraitWAssocConst for impl Demo {
-   |                           ^^^^^^^^^
-
-error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
-  --> $DIR/issue-105330.rs:12:11
-   |
-LL |     foo::<Demo>()();
-   |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
-   |
-note: required by a bound in `foo`
-  --> $DIR/issue-105330.rs:11:11
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
-  --> $DIR/issue-105330.rs:12:11
-   |
-LL |     foo::<Demo>()();
-   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
-   |
-   = note: expected constant `32`
-              found constant `<Demo as TraitWAssocConst>::A`
-note: required by a bound in `foo`
-  --> $DIR/issue-105330.rs:11:28
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |                            ^^^^ required by this bound in `foo`
-
-error[E0618]: expected function, found `()`
-  --> $DIR/issue-105330.rs:12:5
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   | ----------------------------------- `foo::<Demo>` defined here returns `()`
-LL |     foo::<Demo>()();
-   |     ^^^^^^^^^^^^^--
-   |     |
-   |     call expression requires function
-
-error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
-  --> $DIR/issue-105330.rs:19:11
-   |
-LL |     foo::<Demo>();
-   |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
-   |
-note: required by a bound in `foo`
-  --> $DIR/issue-105330.rs:11:11
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
-  --> $DIR/issue-105330.rs:19:11
-   |
-LL |     foo::<Demo>();
-   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
-   |
-   = note: expected constant `32`
-              found constant `<Demo as TraitWAssocConst>::A`
-note: required by a bound in `foo`
-  --> $DIR/issue-105330.rs:11:28
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |                            ^^^^ required by this bound in `foo`
-
-error[E0131]: `main` function is not allowed to have generic parameters
-  --> $DIR/issue-105330.rs:17:8
-   |
-LL | fn main<A: TraitWAssocConst<A=32>>() {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
-
-error: aborting due to 11 previous errors
-
-Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
-For more information about an error, try `rustc --explain E0131`.
diff --git a/src/test/ui/issues/issue-10536.rs b/src/test/ui/issues/issue-10536.rs
deleted file mode 100644 (file)
index f536d8f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// We only want to assert that this doesn't ICE, we don't particularly care
-// about whether it nor it fails to compile.
-
-macro_rules! foo{
-    () => {{
-        macro_rules! bar{() => (())}
-        1
-    }}
-}
-
-pub fn main() {
-    foo!();
-
-    assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
-
-    // regardless of whether nested macro_rules works, the following should at
-    // least throw a conventional error.
-    assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
-}
diff --git a/src/test/ui/issues/issue-10536.stderr b/src/test/ui/issues/issue-10536.stderr
deleted file mode 100644 (file)
index cc04844..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: expected one of `(`, `[`, or `{`, found `two`
-  --> $DIR/issue-10536.rs:14:19
-   |
-LL |     assert!({one! two()});
-   |                   ^^^ expected one of `(`, `[`, or `{`
-
-error: expected one of `(`, `[`, or `{`, found `two`
-  --> $DIR/issue-10536.rs:18:19
-   |
-LL |     assert!({one! two});
-   |                   ^^^ expected one of `(`, `[`, or `{`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/issues/issue-10626.rs b/src/test/ui/issues/issue-10626.rs
deleted file mode 100644 (file)
index 696a2dd..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-// Make sure that if a process doesn't have its stdio/stderr descriptors set up
-// that we don't die in a large ball of fire
-
-use std::env;
-use std::process::{Command, Stdio};
-
-pub fn main () {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "child" {
-        for _ in 0..1000 {
-            println!("hello?");
-        }
-        for _ in 0..1000 {
-            println!("hello?");
-        }
-        return;
-    }
-
-    let mut p = Command::new(&args[0]);
-    p.arg("child").stdout(Stdio::null()).stderr(Stdio::null());
-    println!("{:?}", p.spawn().unwrap().wait());
-}
index 15b2bbeb7c29526b1bfb1a223ff465cf227dbca0..ace77814a3a99d6aeffe811f76805ba85b7c579d 100644 (file)
@@ -6,7 +6,7 @@ LL |     c.read_to(v);
    |       |       |
    |       |       expected `&mut [u8]`, found struct `Vec`
    |       |       help: consider mutably borrowing here: `&mut v`
-   |       arguments to this function are incorrect
+   |       arguments to this method are incorrect
    |
    = note: expected mutable reference `&mut [u8]`
                          found struct `Vec<_>`
index 7631831a81a5b2787be1811730173a858a65e188..fdb356e70c5f06d0a0994733830fddafc87872a8 100644 (file)
@@ -7,8 +7,8 @@ trait Foo {
 impl Foo for Baz {
     fn bar(&mut self, other: &dyn Foo) {}
     //~^ ERROR method `bar` has an incompatible type for trait
-    //~| expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
-    //~| found fn pointer `fn(&mut Baz, &dyn Foo)`
+    //~| expected signature `fn(&mut Baz, &mut dyn Foo)`
+    //~| found signature `fn(&mut Baz, &dyn Foo)`
 }
 
 fn main() {}
index 72e549813e81c340fb0cc93c432f05ce0e45480f..db2c1189e1e1a408dce972af37da90f7c46094b5 100644 (file)
@@ -12,8 +12,8 @@ note: type in trait
    |
 LL |     fn bar(&mut self, other: &mut dyn Foo);
    |                              ^^^^^^^^^^^^
-   = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
-              found fn pointer `fn(&mut Baz, &dyn Foo)`
+   = note: expected signature `fn(&mut Baz, &mut dyn Foo)`
+              found signature `fn(&mut Baz, &dyn Foo)`
 
 error: aborting due to previous error
 
index 3abeadf9e4bbeb12ebb3b27bbd94ecc749fe03eb..a365e24e27e27f53e2671ed5260e6a5e67503494 100644 (file)
@@ -1,10 +1,7 @@
 error[E0515]: cannot return value referencing local variable `rawLines`
   --> $DIR/issue-13497-2.rs:3:5
    |
-LL |        rawLines
-   |  ______^
-   | | _____|
-   | ||
+LL | //     rawLines
 LL | ||         .iter().map(|l| l.trim()).collect()
    | ||_______________-___________________________^ returns a value referencing data owned by the current function
    |  |_______________|
diff --git a/src/test/ui/issues/issue-13655.rs b/src/test/ui/issues/issue-13655.rs
deleted file mode 100644 (file)
index 6dd1847..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-#![feature(fn_traits, unboxed_closures)]
-use std::ops::Fn;
-
-struct Foo<T>(T);
-
-impl<T: Copy> Fn<()> for Foo<T> {
-    extern "rust-call" fn call(&self, _: ()) -> T {
-      match *self {
-        Foo(t) => t
-      }
-    }
-}
-
-impl<T: Copy> FnMut<()> for Foo<T> {
-    extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
-        self.call(())
-    }
-}
-
-impl<T: Copy> FnOnce<()> for Foo<T> {
-    type Output = T;
-
-    extern "rust-call" fn call_once(self, _: ()) -> T {
-        self.call(())
-    }
-}
-
-fn main() {
-  let t: u8 = 1;
-  println!("{}", Foo(t)());
-}
index 132e2b101a5ff1d4c207e69fa9e71951f41cb451..3a43627e69105d5d680185b91a564c4265619797 100644 (file)
@@ -7,7 +7,7 @@ LL | fn fn1(0: Box) {}
 help: add missing generic argument
    |
 LL | fn fn1(0: Box<T>) {}
-   |           ~~~~~~
+   |              +++
 
 error: aborting due to previous error
 
index 71b75a6e7e00f98e018c937249c8e6a892abdc3b..cb27e2bcfb6c07bb7961f9f33dfac8134fb42e2e 100644 (file)
@@ -10,8 +10,8 @@ impl<T: fmt::Debug> ops::FnOnce<(),> for Debuger<T> {
     type Output = ();
     fn call_once(self, _args: ()) {
     //~^ ERROR `call_once` has an incompatible type for trait
-    //~| expected fn pointer `extern "rust-call" fn
-    //~| found fn pointer `fn
+    //~| expected signature `extern "rust-call" fn
+    //~| found signature `fn
         println!("{:?}", self.x);
     }
 }
index 2dcdaba170ac7be73470e95846c54a98c254e711..b7c950892dc29de44ca3e6486b14d20dc5b5001f 100644 (file)
@@ -4,8 +4,8 @@ error[E0053]: method `call_once` has an incompatible type for trait
 LL |     fn call_once(self, _args: ()) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "Rust" fn
    |
-   = note: expected fn pointer `extern "rust-call" fn(Debuger<_>, ())`
-              found fn pointer `fn(Debuger<_>, ())`
+   = note: expected signature `extern "rust-call" fn(Debuger<_>, ())`
+              found signature `fn(Debuger<_>, ())`
 
 error: aborting due to previous error
 
index 22c3470b61edeb955e8cb92b46c1d837c4c241aa..bd18d46223e69162ae8cdd869df402f0d84b35d7 100644 (file)
@@ -1,10 +1,8 @@
 error[E0277]: the trait bound `isize: HasState` is not satisfied
-  --> $DIR/issue-18611.rs:1:1
+  --> $DIR/issue-18611.rs:1:18
    |
-LL | / fn add_state(op: <isize as HasState>::State) {
-LL | |
-LL | | }
-   | |_^ the trait `HasState` is not implemented for `isize`
+LL | fn add_state(op: <isize as HasState>::State) {
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-18937-1.rs b/src/test/ui/issues/issue-18937-1.rs
deleted file mode 100644 (file)
index 57e56d8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// run-pass
-// Test that we are able to type-check this example. In particular,
-// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because
-// when `T=[U]` it implies that `U: 'a`).
-//
-// Regr. test for live code we found in the wild when fixing #18937.
-
-pub trait Leak<T : ?Sized> {
-    fn leak<'a>(self) -> &'a T where T: 'a;
-}
-
-impl<U> Leak<[U]> for Vec<U> {
-    fn leak<'a>(mut self) -> &'a [U] where [U]: 'a {
-        let r: *mut [U] = &mut self[..];
-        std::mem::forget(self);
-        unsafe { &mut *r }
-    }
-}
-fn main() {
-    println!("Hello, world!");
-}
diff --git a/src/test/ui/issues/issue-18937.rs b/src/test/ui/issues/issue-18937.rs
deleted file mode 100644 (file)
index af85e5b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Regression test for #18937.
-
-use std::fmt;
-
-#[derive(Debug)]
-struct MyString<'a>(&'a String);
-
-struct B {
-    list: Vec<Box<dyn fmt::Debug>>,
-}
-
-trait A<'a> {
-    fn foo<F>(&mut self, f: F)
-        where F: fmt::Debug + 'a,
-              Self: Sized;
-}
-
-impl<'a> A<'a> for B {
-    fn foo<F>(&mut self, f: F)
-        where F: fmt::Debug + 'static, //~ ERROR impl has stricter
-    {
-        self.list.push(Box::new(f));
-    }
-}
-
-fn main() {
-    let mut b = B { list: Vec::new() };
-
-    // Create a borrowed pointer, put it in `b`, then drop what's borrowing it
-    let a = "hello".to_string();
-    b.foo(MyString(&a));
-
-    // Drop the data which `b` has a reference to
-    drop(a);
-
-    // Use the data, probably segfaulting
-    for b in b.list.iter() {
-        println!("{:?}", b);
-    }
-}
diff --git a/src/test/ui/issues/issue-18937.stderr b/src/test/ui/issues/issue-18937.stderr
deleted file mode 100644 (file)
index 5e2ba0e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/issue-18937.rs:20:31
-   |
-LL | /     fn foo<F>(&mut self, f: F)
-LL | |         where F: fmt::Debug + 'a,
-LL | |               Self: Sized;
-   | |__________________________- definition of `foo` from trait
-...
-LL |           where F: fmt::Debug + 'static,
-   |                                 ^^^^^^^ impl has extra requirement `F: 'static`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0276`.
index 6f4813ca6235b1cfb1d8a3331d530d1ff06d42f8..5822160107cce5479747543a07da6dfcbe2f3b62 100644 (file)
@@ -9,8 +9,8 @@ LL |   extern "rust-call" fn call(&self, (_,): (T,)) {}
    |                                           expected `&T`, found type parameter `T`
    |                                           help: change the parameter type to match the trait: `(&'a T,)`
    |
-   = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
-              found fn pointer `extern "rust-call" fn(&Foo, (T,))`
+   = note: expected signature `extern "rust-call" fn(&Foo, (&'a T,))`
+              found signature `extern "rust-call" fn(&Foo, (T,))`
 
 error[E0053]: method `call_mut` has an incompatible type for trait
   --> $DIR/issue-20225.rs:11:51
@@ -23,8 +23,8 @@ LL |   extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
    |                                                   expected `&T`, found type parameter `T`
    |                                                   help: change the parameter type to match the trait: `(&'a T,)`
    |
-   = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
-              found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
+   = note: expected signature `extern "rust-call" fn(&mut Foo, (&'a T,))`
+              found signature `extern "rust-call" fn(&mut Foo, (T,))`
 
 error[E0053]: method `call_once` has an incompatible type for trait
   --> $DIR/issue-20225.rs:18:47
@@ -38,8 +38,8 @@ LL |   extern "rust-call" fn call_once(self, (_,): (T,)) {}
    |                                               expected `&T`, found type parameter `T`
    |                                               help: change the parameter type to match the trait: `(&'a T,)`
    |
-   = note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
-              found fn pointer `extern "rust-call" fn(Foo, (T,))`
+   = note: expected signature `extern "rust-call" fn(Foo, (&'a T,))`
+              found signature `extern "rust-call" fn(Foo, (T,))`
 
 error: aborting due to 3 previous errors
 
index ef62dece8364002a54f8cb4b760740c426bf57d7..c3af1f6786b34a01a1b003b1fd8609cd33af3385 100644 (file)
@@ -1,14 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/issue-20831-debruijn.rs:28:5
+  --> $DIR/issue-20831-debruijn.rs:28:33
    |
-LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-LL | |         // Not obvious, but there is an implicit lifetime here -------^
-LL | |
-LL | |         //
-...  |
-LL | |         self.sub = t;
-LL | |     }
-   | |_____^
+LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the anonymous lifetime defined here...
   --> $DIR/issue-20831-debruijn.rs:28:58
@@ -21,16 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined he
 LL | impl<'a> Publisher<'a> for MyStruct<'a> {
    |      ^^
 note: ...so that the types are compatible
-  --> $DIR/issue-20831-debruijn.rs:28:5
+  --> $DIR/issue-20831-debruijn.rs:28:33
    |
-LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-LL | |         // Not obvious, but there is an implicit lifetime here -------^
-LL | |
-LL | |         //
-...  |
-LL | |         self.sub = t;
-LL | |     }
-   | |_____^
+LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected `<MyStruct<'a> as Publisher<'_>>`
               found `<MyStruct<'_> as Publisher<'_>>`
 
index d92966da17c4ceb7e2db6a3fb02c81a502cf3560..0e1beebf2931a2e01c2658a2f0264f8aed6302fd 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn next(&mut self) -> Result<i32, i32> { Ok(7) }
    |                           expected enum `Option`, found enum `Result`
    |                           help: change the output type to match the trait: `Option<i32>`
    |
-   = note: expected fn pointer `fn(&mut S) -> Option<i32>`
-              found fn pointer `fn(&mut S) -> Result<i32, i32>`
+   = note: expected signature `fn(&mut S) -> Option<i32>`
+              found signature `fn(&mut S) -> Result<i32, i32>`
 
 error: aborting due to previous error
 
index 72c65029746adb83a8aaa15d71eca77667e8860c..04379f07ba0f78ff1a81c7d0654c059c7aa1819c 100644 (file)
@@ -7,7 +7,7 @@ LL |     foo::<HashMap<Rc<()>, Rc<()>>>();
    = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`
    = note: required because it appears within the type `(Rc<()>, Rc<()>)`
    = note: required for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` to implement `Send`
-   = note: required because it appears within the type `hashbrown::map::HashMap<Rc<()>, Rc<()>, RandomState>`
+   = note: required because it appears within the type `HashMap<Rc<()>, Rc<()>, RandomState>`
    = note: required because it appears within the type `HashMap<Rc<()>, Rc<()>>`
 note: required by a bound in `foo`
   --> $DIR/issue-21763.rs:6:11
index 014eb2897b488871c5f0ea563ab1a30bea8119fd..2c325ffcceeaa0d6064be4e5fb64829f19739cf8 100644 (file)
@@ -16,7 +16,7 @@ LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
 help: add missing generic argument
    |
 LL |     println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
-   |                                       ~~~~~~~~
+   |                                         ++++++
 
 error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified
   --> $DIR/issue-23024.rs:8:39
index a76d8a615f6c208b0381b405b99db91148a5d2c7..b26cc77680daa2181d847e26edc30596ed22c286 100644 (file)
@@ -24,5 +24,4 @@ macro_rules! check_ptr_exist {
 fn main() {
     let item = stuff::Item::new();
     println!("{}", check_ptr_exist!(item, name));
-    //~^ ERROR field `name` of struct `CObj` is private
 }
index bce269393eec4ba6ca6677d0e79140c1711e929d..727b96908291e589eeb493fe0cc1bd02ae88a307 100644 (file)
@@ -9,12 +9,6 @@ LL |     println!("{}", check_ptr_exist!(item, name));
    |
    = note: this error originates in the macro `check_ptr_exist` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0616]: field `name` of struct `CObj` is private
-  --> $DIR/issue-25386.rs:26:43
-   |
-LL |     println!("{}", check_ptr_exist!(item, name));
-   |                                           ^^^^ private field
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0616`.
index 325c28c15e2723566e4829c061863f5dba32fd1e..dadae23fdf39989a69f63b5546e882ef92ab0a88 100644 (file)
@@ -2,12 +2,17 @@ error[E0644]: closure/generator type that references itself
   --> $DIR/issue-25439.rs:8:9
    |
 LL |     fix(|_, x| x);
-   |         ^^^^^^^^ cyclic type of infinite size
+   |         ^^^^^^ cyclic type of infinite size
    |
    = note: closures cannot capture themselves or take themselves as argument;
            this error may be the result of a recent compiler bug-fix,
            see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
            for more information
+note: required by a bound in `fix`
+  --> $DIR/issue-25439.rs:3:33
+   |
+LL | fn fix<F>(f: F) -> i32 where F: Fn(Helper<F>, i32) -> i32 {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `fix`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-25700-1.rs b/src/test/ui/issues/issue-25700-1.rs
deleted file mode 100644 (file)
index 5e71a52..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
-
-trait Tr { type Out; }
-impl<T> Tr for T { type Out = T; }
-
-impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
-impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
-    fn clone(&self) -> Self { *self }
-}
-fn main() {
-    S::<()>(None);
-}
diff --git a/src/test/ui/issues/issue-25700-2.rs b/src/test/ui/issues/issue-25700-2.rs
deleted file mode 100644 (file)
index 89b1db4..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-pass
-pub trait Parser {
-    type Input;
-}
-
-pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
-
-#[allow(unused_tuple_struct_fields)]
-pub struct Map<P, F>(P, F);
-impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
-    type Input = u8;
-}
-
-trait AstId { type Untyped; }
-impl AstId for u32 { type Untyped = u32; }
-
-fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
-    Iter(Map(i, |_: Id::Untyped| {}), 42).1
-}
-
-pub fn main() {
-    assert_eq!(record_type::<u32>(3), 42);
-}
diff --git a/src/test/ui/issues/issue-25700.rs b/src/test/ui/issues/issue-25700.rs
deleted file mode 100644 (file)
index e5b9a97..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
-
-trait Tr { type Out; }
-impl<T> Tr for T { type Out = T; }
-
-impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
-impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
-    fn clone(&self) -> Self { *self }
-}
-fn main() {
-    let t = S::<()>(None);
-    drop(t);
-    drop(t); //~ ERROR use of moved value
-}
diff --git a/src/test/ui/issues/issue-25700.stderr b/src/test/ui/issues/issue-25700.stderr
deleted file mode 100644 (file)
index fa309a5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0382]: use of moved value: `t`
-  --> $DIR/issue-25700.rs:13:10
-   |
-LL |     let t = S::<()>(None);
-   |         - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait
-LL |     drop(t);
-   |          - value moved here
-LL |     drop(t);
-   |          ^ value used here after move
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0382`.
index df8c2f739108db485ed7b8a1ed782e532fd4a545..d3d670aa92aeb23f30f39050dde6041894241caa 100644 (file)
@@ -8,6 +8,6 @@ fn some_function() {} //~ NOTE defined here
 
 fn main() {
     some_macro!(some_function);
-    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+    //~^ ERROR function takes 0 arguments but 1 argument was supplied
     //~| NOTE in this expansion of some_macro!
 }
diff --git a/src/test/ui/issues/issue-2734.rs b/src/test/ui/issues/issue-2734.rs
deleted file mode 100644 (file)
index df4f394..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
-
-// pretty-expanded FIXME #23616
-
-trait hax {
-    fn dummy(&self) { }
-}
-impl<A> hax for A { }
-
-fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
-    Box::new(x) as Box<dyn hax+'static>
-}
-
-fn deadcode() {
-    perform_hax(Box::new("deadcode".to_string()));
-}
-
-pub fn main() {
-    let _ = perform_hax(Box::new(42));
-}
index ce91022f093d4461749b58f3316cc31b18c6949a..399e9ba0df73053982325f68abd8e5e324012092 100644 (file)
@@ -1,5 +1,7 @@
 // test for https://github.com/rust-lang/rust/issues/29723
 
+#![feature(if_let_guard)]
+
 fn main() {
     let s = String::new();
     let _s = match 0 {
@@ -11,4 +13,10 @@ fn main() {
             //~^ ERROR use of moved value: `s`
         }
     };
+
+    let s = String::new();
+    let _s = match 0 {
+        0 if let Some(()) = { drop(s); None } => String::from("oops"),
+        _ => s //~ ERROR use of moved value: `s`
+    };
 }
index 92ee5cf22b719a7fa8a5e573fbbf073443be0f7e..044d8a9b5dd1d6a33b99033963cbf40162b18aed 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `s`
-  --> $DIR/issue-29723.rs:10:13
+  --> $DIR/issue-29723.rs:12:13
    |
 LL |     let s = String::new();
    |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         0 if { drop(s.clone()); false } => String::from("oops"),
    |                      ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `s`
+  --> $DIR/issue-29723.rs:20:14
+   |
+LL |     let s = String::new();
+   |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
+LL |     let _s = match 0 {
+LL |         0 if let Some(()) = { drop(s); None } => String::from("oops"),
+   |                                    - value moved here
+LL |         _ => s
+   |              ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
+   |                                     ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/issues/issue-31173.rs b/src/test/ui/issues/issue-31173.rs
deleted file mode 100644 (file)
index f678df5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-use std::vec::IntoIter;
-
-pub fn get_tok(it: &mut IntoIter<u8>) {
-    let mut found_e = false;
-
-    let temp: Vec<u8> = it
-        .take_while(|&x| {
-            found_e = true;
-            false
-        })
-        .cloned() //~ ERROR to be an iterator that yields `&_`, but it yields `u8`
-        .collect(); //~ ERROR the method
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr
deleted file mode 100644 (file)
index f3be99f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
-  --> $DIR/issue-31173.rs:11:10
-   |
-LL |         .cloned()
-   |          ^^^^^^ expected reference, found `u8`
-   |
-   = note: expected reference `&_`
-                   found type `u8`
-note: the method call chain might not have had the expected associated types
-  --> $DIR/issue-31173.rs:3:20
-   |
-LL |   pub fn get_tok(it: &mut IntoIter<u8>) {
-   |                      ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
-...
-LL |           .take_while(|&x| {
-   |  __________-
-LL | |             found_e = true;
-LL | |             false
-LL | |         })
-   | |__________- `Iterator::Item` remains `u8` here
-note: required by a bound in `cloned`
-  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
-  --> $DIR/issue-31173.rs:12:10
-   |
-LL |         .collect();
-   |          ^^^^^^^ method cannot be called due to unsatisfied trait bounds
-  --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
-   |
-   = note: doesn't satisfy `<_ as Iterator>::Item = &_`
-  --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
-   |
-   = note: doesn't satisfy `_: Iterator`
-   |
-   = note: the following trait bounds were not satisfied:
-           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
-           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
-           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
-           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0271, E0599.
-For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/issues/issue-34053.rs b/src/test/ui/issues/issue-34053.rs
deleted file mode 100644 (file)
index fa23ae8..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// run-pass
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
-
-struct A(i32);
-
-impl Drop for A {
-    fn drop(&mut self) {
-        // update global drop count
-        DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
-    }
-}
-
-static FOO: A = A(123);
-const BAR: A = A(456);
-
-impl A {
-    const BAZ: A = A(789);
-}
-
-fn main() {
-    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
-    assert_eq!(&FOO.0, &123);
-    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
-    assert_eq!(BAR.0, 456);
-    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 1);
-    assert_eq!(A::BAZ.0, 789);
-    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
-}
index ebc40f6786fd0a403bfe52554028f0cce3299195..3dc33729d8fdb1394e8cb6869899c1cbc719bdfd 100644 (file)
@@ -1,3 +1,9 @@
+error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
+  --> $DIR/issue-35570.rs:8:40
+   |
+LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
+
 error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
   --> $DIR/issue-35570.rs:8:1
    |
@@ -8,12 +14,6 @@ LL | |     let _e: (usize, usize) = unsafe{mem::transmute(param)};
 LL | | }
    | |_^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
 
-error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
-  --> $DIR/issue-35570.rs:8:40
-   |
-LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
-
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 3b37578f3c4551497c0a7a523839b32b548da32e..5b753c69d5d10a419e720d44054f263f3e032558 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
   --> $DIR/issue-36400.rs:5:7
    |
-LL |     let x = Box::new(3);
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     f(&mut *x);
    |       ^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = Box::new(3);
+   |         +++
 
 error: aborting due to previous error
 
index e9f50b41f6acd9207133c17325dfaa4b02e240ac..7ddb36c8e6f7f406b54299c98fba8cbf7cb1c92f 100644 (file)
@@ -4,8 +4,8 @@ error[E0308]: method not compatible with trait
 LL |     fn next(&'a mut self) -> Option<Self::Item>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>`
-              found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
+   = note: expected signature `fn(&mut RepeatMut<'a, T>) -> Option<_>`
+              found signature `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
 note: the anonymous lifetime as defined here...
   --> $DIR/issue-37884.rs:6:5
    |
index da3e62e35dc81b804a35254dfe8f9797e619606c..60bbfc0c6e2696336ce75aa8992697784fa8829e 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     b"".starts_with(stringify!(foo))
    |         ----------- ^^^^^^^^^^^^^^^ expected slice `[u8]`, found `str`
    |         |
-   |         arguments to this function are incorrect
+   |         arguments to this method are incorrect
    |
    = note: expected reference `&[u8]`
               found reference `&'static str`
index b342bbb1b8eab90d69c2b0f3ea61100b7654413e..c95020a0c006c9176186239a3b33f8d5246f7427 100644 (file)
@@ -3,4 +3,4 @@
 fn foo(a: usize) {}
 //~^ defined here
 fn main() { foo(5, 6) }
-//~^ ERROR this function takes 1 argument but 2 arguments were supplied
+//~^ ERROR function takes 1 argument but 2 arguments were supplied
index 067bdef8b6746c73a645eda9e50115ebbae0ebac..c4e61e719539280b1bc96b9e87fae6ae4c180ffd 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
   --> $DIR/issue-51515.rs:5:5
    |
-LL |     let foo = &16;
-   |               --- help: consider changing this to be a mutable reference: `&mut 16`
-...
 LL |     *foo = 32;
    |     ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let foo = &mut 16;
+   |               ~~~~~~~
 
 error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
   --> $DIR/issue-51515.rs:8:5
diff --git a/src/test/ui/issues/issue-54189.rs b/src/test/ui/issues/issue-54189.rs
deleted file mode 100644 (file)
index 70aecc3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
-//~^ ERROR binding for associated type `Output` references lifetime `'r`
-
-fn main() {
-    let f = bug();
-}
diff --git a/src/test/ui/issues/issue-54189.stderr b/src/test/ui/issues/issue-54189.stderr
deleted file mode 100644 (file)
index 4787abd..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types
-  --> $DIR/issue-54189.rs:1:35
-   |
-LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
-   |                                   ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0582`.
index f654605423379849b5788867d7fa14b2bf3e6aca..5fcc338557c58c9e9c01a25b1f0ad5184d2d4ef6 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*x.1` as mutable, as it is behind a `&` reference
   --> $DIR/issue-61623.rs:6:19
    |
-LL | fn f3<'a>(x: &'a ((), &'a mut ())) {
-   |              -------------------- help: consider changing this to be a mutable reference: `&'a mut ((), &'a mut ())`
 LL |     f2(|| x.0, f1(x.1))
    |                   ^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn f3<'a>(x: &'a mut ((), &'a mut ())) {
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-67535.rs b/src/test/ui/issues/issue-67535.rs
new file mode 100644 (file)
index 0000000..24f5062
--- /dev/null
@@ -0,0 +1,22 @@
+fn main() {}
+
+impl std::ops::AddAssign for () {
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    fn add_assign(&self, other: ()) -> () {
+        ()
+    }
+}
+
+impl std::ops::AddAssign for [(); 1] {
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    fn add_assign(&self, other: [(); 1]) -> [(); 1] {
+        [()]
+    }
+}
+
+impl std::ops::AddAssign for &[u8] {
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    fn add_assign(&self, other: &[u8]) -> &[u8] {
+        self
+    }
+}
diff --git a/src/test/ui/issues/issue-67535.stderr b/src/test/ui/issues/issue-67535.stderr
new file mode 100644 (file)
index 0000000..4d7a02a
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/issue-67535.rs:3:1
+   |
+LL | impl std::ops::AddAssign for () {
+   | ^^^^^-------------------^^^^^--
+   | |    |                       |
+   | |    |                       this is not defined in the current crate because tuples are always foreign
+   | |    this is not defined in the current crate because this is a foreign trait
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/issue-67535.rs:10:1
+   |
+LL | impl std::ops::AddAssign for [(); 1] {
+   | ^^^^^-------------------^^^^^-------
+   | |    |                       |
+   | |    |                       this is not defined in the current crate because arrays are always foreign
+   | |    this is not defined in the current crate because this is a foreign trait
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/issue-67535.rs:17:1
+   |
+LL | impl std::ops::AddAssign for &[u8] {
+   | ^^^^^-------------------^^^^^-----
+   | |    |                       |
+   | |    |                       this is not defined in the current crate because slices are always foreign
+   | |    this is not defined in the current crate because this is a foreign trait
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs
deleted file mode 100644 (file)
index 54f7e9a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-use std::collections::BTreeSet;
-
-#[derive(Hash)]
-pub enum ElemDerived {
-    //~^ ERROR recursive type `ElemDerived` has infinite size
-    A(ElemDerived)
-}
-
-
-pub enum Elem {
-    Derived(ElemDerived)
-}
-
-pub struct Set(BTreeSet<Elem>);
-
-impl Set {
-    pub fn into_iter(self) -> impl Iterator<Item = Elem> {
-        self.0.into_iter()
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr
deleted file mode 100644 (file)
index d12be53..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0072]: recursive type `ElemDerived` has infinite size
-  --> $DIR/issue-72554.rs:4:1
-   |
-LL | pub enum ElemDerived {
-   | ^^^^^^^^^^^^^^^^^^^^
-LL |
-LL |     A(ElemDerived)
-   |       ----------- recursive without indirection
-   |
-help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
-   |
-LL |     A(Box<ElemDerived>)
-   |       ++++           +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/issues/issue-82859-slice-miscompile.rs b/src/test/ui/issues/issue-82859-slice-miscompile.rs
deleted file mode 100644 (file)
index b64eb49..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-// compile-flags: -Copt-level=0 -Cdebuginfo=2
-
-// Make sure LLVM does not miscompile this.
-
-fn indirect_get_slice() -> &'static [usize] {
-    &[]
-}
-
-#[inline(always)]
-fn get_slice() -> &'static [usize] {
-    let ret = indirect_get_slice();
-    ret
-}
-
-fn main() {
-    let output = get_slice().len();
-    assert_eq!(output, 0);
-}
index 693cfecedc4bd9097b1becee84099b8246238730..6c5917bdf6ece356714697546ba3c38ecfb7a5e8 100644 (file)
@@ -42,7 +42,7 @@ LL | trait Foo<T, T = T> {}
 help: add missing generic argument
    |
 LL |     eq::<dyn, Foo<T>>
-   |               ~~~~~~
+   |                  +++
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/issues/issue-99875.rs b/src/test/ui/issues/issue-99875.rs
deleted file mode 100644 (file)
index cf73fd8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-struct Argument;
-struct Return;
-
-fn function(_: Argument) -> Return { todo!() }
-
-trait Trait {}
-impl Trait for fn(Argument) -> Return {}
-
-fn takes(_: impl Trait) {}
-
-fn main() {
-    takes(function);
-    //~^ ERROR the trait bound
-    takes(|_: Argument| -> Return { todo!() });
-    //~^ ERROR the trait bound
-}
diff --git a/src/test/ui/issues/issue-99875.stderr b/src/test/ui/issues/issue-99875.stderr
deleted file mode 100644 (file)
index 3ff8f12..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
-  --> $DIR/issue-99875.rs:12:11
-   |
-LL |     takes(function);
-   |     ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
-note: required by a bound in `takes`
-  --> $DIR/issue-99875.rs:9:18
-   |
-LL | fn takes(_: impl Trait) {}
-   |                  ^^^^^ required by this bound in `takes`
-
-error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
-  --> $DIR/issue-99875.rs:14:11
-   |
-LL |     takes(|_: Argument| -> Return { todo!() });
-   |     ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `[closure@$DIR/issue-99875.rs:14:11: 14:34]`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
-note: required by a bound in `takes`
-  --> $DIR/issue-99875.rs:9:18
-   |
-LL | fn takes(_: impl Trait) {}
-   |                  ^^^^^ required by this bound in `takes`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/layout/thin-meta-implies-thin-ptr.rs b/src/test/ui/layout/thin-meta-implies-thin-ptr.rs
new file mode 100644 (file)
index 0000000..972579e
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(ptr_metadata)]
+
+use std::ptr::Thin;
+
+fn main() {}
+
+fn foo<T: ?Sized + Thin>(t: *const T) -> *const () {
+    unsafe { std::mem::transmute(t) }
+}
index 697a7c28da16d5743bcd23728fd040ad5383b9a2..ecbdb14dc868e502fde7ffd64cc40a36c2b95f96 100644 (file)
@@ -49,6 +49,8 @@ error: integer literal is too large
    |
 LL |     999340282366920938463463374607431768211455999;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
 
 error: aborting due to 8 previous errors
 
index 4379b4fa6d777b53006a85a3360e2b9a1b6c52b5..1b498c0fbca67cc05cb75d31072d0296c3cbfd3f 100644 (file)
@@ -7,10 +7,8 @@ fn main() {
     //~^ ERROR: character literal may only contain one codepoint
 
     if x == y {}
-    //~^ ERROR: can't compare `&str` with `char`
     if y == z {}  // no error here
     if x == z {}
-    //~^ ERROR: can't compare `&str` with `char`
 
     let a: usize = "";
     //~^ ERROR: mismatched types
index ce41942467cea1a9fb34bcfe201485e2cbd3bd34..2fe30304a50d694709c25690f35d4d432cb9d538 100644 (file)
@@ -31,49 +31,14 @@ help: if you meant to write a `str` literal, use double quotes
 LL |     let z = "ef";
    |             ~~~~
 
-error[E0277]: can't compare `&str` with `char`
-  --> $DIR/lex-bad-char-literals-6.rs:9:10
-   |
-LL |     if x == y {}
-   |          ^^ no implementation for `&str == char`
-   |
-   = help: the trait `PartialEq<char>` is not implemented for `&str`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             <&'a str as PartialEq<OsString>>
-             <&'a str as PartialEq<String>>
-             <&'b str as PartialEq<Cow<'a, str>>>
-             <str as PartialEq<Cow<'a, str>>>
-             <str as PartialEq<OsStr>>
-             <str as PartialEq<OsString>>
-             <str as PartialEq<String>>
-             <str as PartialEq>
-
 error[E0308]: mismatched types
-  --> $DIR/lex-bad-char-literals-6.rs:15:20
+  --> $DIR/lex-bad-char-literals-6.rs:13:20
    |
 LL |     let a: usize = "";
    |            -----   ^^ expected `usize`, found `&str`
    |            |
    |            expected due to this
 
-error[E0277]: can't compare `&str` with `char`
-  --> $DIR/lex-bad-char-literals-6.rs:12:10
-   |
-LL |     if x == z {}
-   |          ^^ no implementation for `&str == char`
-   |
-   = help: the trait `PartialEq<char>` is not implemented for `&str`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             <&'a str as PartialEq<OsString>>
-             <&'a str as PartialEq<String>>
-             <&'b str as PartialEq<Cow<'a, str>>>
-             <str as PartialEq<Cow<'a, str>>>
-             <str as PartialEq<OsStr>>
-             <str as PartialEq<OsString>>
-             <str as PartialEq<String>>
-             <str as PartialEq>
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
index cf8440ca488ccaeeff1e75c5d2809b9bb1c851ad..56bdc50e40d689031f729d6ec7408e8bad88e3c8 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-tidy-linelength
+
 fn main() {
     0o1.0; //~ ERROR: octal float literal is not supported
     0o2f32; //~ ERROR: octal float literal is not supported
@@ -15,6 +17,12 @@ fn main() {
     //~^ ERROR: integer literal is too large
     9900000000000000000000000000999999999999999999999999999999;
     //~^ ERROR: integer literal is too large
+    0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110;
+    //~^ ERROR: integer literal is too large
+    0o37777777777777777777777777777777777777777770;
+    //~^ ERROR: integer literal is too large
+    0xffffffffffffffffffffffffffffffff0;
+    //~^ ERROR: integer literal is too large
     0x; //~ ERROR: no valid digits
     0xu32; //~ ERROR: no valid digits
     0ou32; //~ ERROR: no valid digits
index f05d61603023cbb1c9224dc1a7e42f37c1d1c87e..1457541970af456b03d709f22c7baa2f893ce050 100644 (file)
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:2:5
+  --> $DIR/lex-bad-numeric-literals.rs:4:5
    |
 LL |     0o1.0;
    |     ^^^^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:4:5
+  --> $DIR/lex-bad-numeric-literals.rs:6:5
    |
 LL |     0o3.0f32;
    |     ^^^^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:5:5
+  --> $DIR/lex-bad-numeric-literals.rs:7:5
    |
 LL |     0o4e4;
    |     ^^^^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:6:5
+  --> $DIR/lex-bad-numeric-literals.rs:8:5
    |
 LL |     0o5.0e5;
    |     ^^^^^^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:7:5
+  --> $DIR/lex-bad-numeric-literals.rs:9:5
    |
 LL |     0o6e6f32;
    |     ^^^^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:8:5
+  --> $DIR/lex-bad-numeric-literals.rs:10:5
    |
 LL |     0o7.0e7f64;
    |     ^^^^^^^
 
 error: hexadecimal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:9:5
+  --> $DIR/lex-bad-numeric-literals.rs:11:5
    |
 LL |     0x8.0e+9;
    |     ^^^^^^^^
 
 error: hexadecimal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:10:5
+  --> $DIR/lex-bad-numeric-literals.rs:12:5
    |
 LL |     0x9.0e-9;
    |     ^^^^^^^^
 
 error[E0768]: no valid digits found for number
-  --> $DIR/lex-bad-numeric-literals.rs:11:5
+  --> $DIR/lex-bad-numeric-literals.rs:13:5
    |
 LL |     0o;
    |     ^^
 
 error: expected at least one digit in exponent
-  --> $DIR/lex-bad-numeric-literals.rs:12:5
+  --> $DIR/lex-bad-numeric-literals.rs:14:5
    |
 LL |     1e+;
    |     ^^^
 
 error: hexadecimal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:13:5
+  --> $DIR/lex-bad-numeric-literals.rs:15:5
    |
 LL |     0x539.0;
    |     ^^^^^^^
 
 error[E0768]: no valid digits found for number
-  --> $DIR/lex-bad-numeric-literals.rs:18:5
+  --> $DIR/lex-bad-numeric-literals.rs:26:5
    |
 LL |     0x;
    |     ^^
 
 error[E0768]: no valid digits found for number
-  --> $DIR/lex-bad-numeric-literals.rs:19:5
+  --> $DIR/lex-bad-numeric-literals.rs:27:5
    |
 LL |     0xu32;
    |     ^^
 
 error[E0768]: no valid digits found for number
-  --> $DIR/lex-bad-numeric-literals.rs:20:5
+  --> $DIR/lex-bad-numeric-literals.rs:28:5
    |
 LL |     0ou32;
    |     ^^
 
 error[E0768]: no valid digits found for number
-  --> $DIR/lex-bad-numeric-literals.rs:21:5
+  --> $DIR/lex-bad-numeric-literals.rs:29:5
    |
 LL |     0bu32;
    |     ^^
 
 error[E0768]: no valid digits found for number
-  --> $DIR/lex-bad-numeric-literals.rs:22:5
+  --> $DIR/lex-bad-numeric-literals.rs:30:5
    |
 LL |     0b;
    |     ^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:24:5
+  --> $DIR/lex-bad-numeric-literals.rs:32:5
    |
 LL |     0o123.456;
    |     ^^^^^^^^^
 
 error: binary float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:26:5
+  --> $DIR/lex-bad-numeric-literals.rs:34:5
    |
 LL |     0b111.101;
    |     ^^^^^^^^^
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:3:5
+  --> $DIR/lex-bad-numeric-literals.rs:5:5
    |
 LL |     0o2f32;
    |     ^^^^^^ not supported
 
 error: integer literal is too large
-  --> $DIR/lex-bad-numeric-literals.rs:14:5
+  --> $DIR/lex-bad-numeric-literals.rs:16:5
    |
 LL |     9900000000000000000000000000999999999999999999999999999999;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
 
 error: integer literal is too large
-  --> $DIR/lex-bad-numeric-literals.rs:16:5
+  --> $DIR/lex-bad-numeric-literals.rs:18:5
    |
 LL |     9900000000000000000000000000999999999999999999999999999999;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
+
+error: integer literal is too large
+  --> $DIR/lex-bad-numeric-literals.rs:20:5
+   |
+LL |     0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `0b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111`
+
+error: integer literal is too large
+  --> $DIR/lex-bad-numeric-literals.rs:22:5
+   |
+LL |     0o37777777777777777777777777777777777777777770;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `0o3777777777777777777777777777777777777777777`
+
+error: integer literal is too large
+  --> $DIR/lex-bad-numeric-literals.rs:24:5
+   |
+LL |     0xffffffffffffffffffffffffffffffff0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `0xffffffffffffffffffffffffffffffff`
 
 error: octal float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:23:5
+  --> $DIR/lex-bad-numeric-literals.rs:31:5
    |
 LL |     0o123f64;
    |     ^^^^^^^^ not supported
 
 error: binary float literal is not supported
-  --> $DIR/lex-bad-numeric-literals.rs:25:5
+  --> $DIR/lex-bad-numeric-literals.rs:33:5
    |
 LL |     0b101f64;
    |     ^^^^^^^^ not supported
 
-error: aborting due to 23 previous errors
+error: aborting due to 26 previous errors
 
 For more information about this error, try `rustc --explain E0768`.
diff --git a/src/test/ui/lifetimes/issue-105227.fixed b/src/test/ui/lifetimes/issue-105227.fixed
new file mode 100644 (file)
index 0000000..f6ed9c8
--- /dev/null
@@ -0,0 +1,26 @@
+// Regression test for issue #105227.
+
+// run-rustfix
+#![allow(warnings)]
+fn chars0<'a>(v :(&'a  str, &'a str)) -> impl Iterator<Item = char> + 'a  {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+    v.0.chars().chain(v.1.chars())
+    //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+}
+
+fn chars1<'a>(v0 : &'a  str, v1 : &'a str) -> impl Iterator<Item = char> + 'a  {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+    v0.chars().chain(v1.chars())
+    //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn chars2<'b>(v0 : &'b str, v1 : &'b str, v2 : &'b str) ->
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b`
+    (impl Iterator<Item = char> + 'b , &'b str)
+{
+    (v0.chars().chain(v1.chars()), v2)
+    //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn main() {
+}
diff --git a/src/test/ui/lifetimes/issue-105227.rs b/src/test/ui/lifetimes/issue-105227.rs
new file mode 100644 (file)
index 0000000..6427a50
--- /dev/null
@@ -0,0 +1,26 @@
+// Regression test for issue #105227.
+
+// run-rustfix
+#![allow(warnings)]
+fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+    v.0.chars().chain(v.1.chars())
+    //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+}
+
+fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> {
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+    v0.chars().chain(v1.chars())
+    //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) ->
+//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b`
+    (impl Iterator<Item = char>, &'b str)
+{
+    (v0.chars().chain(v1.chars()), v2)
+    //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound
+}
+
+fn main() {
+}
diff --git a/src/test/ui/lifetimes/issue-105227.stderr b/src/test/ui/lifetimes/issue-105227.stderr
new file mode 100644 (file)
index 0000000..d211459
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+  --> $DIR/issue-105227.rs:7:5
+   |
+LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> {
+   |               ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
+LL |
+LL |     v.0.chars().chain(v.1.chars())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+   |
+LL | fn chars0<'a>(v :(&'a  str, &'a str)) -> impl Iterator<Item = char> + 'a  {
+   |          ++++      ++        ++                                     ++++
+
+error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+  --> $DIR/issue-105227.rs:13:5
+   |
+LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> {
+   |                ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
+LL |
+LL |     v0.chars().chain(v1.chars())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a`
+   |
+LL | fn chars1<'a>(v0 : &'a  str, v1 : &'a str) -> impl Iterator<Item = char> + 'a  {
+   |          ++++       ++             ++                                    ++++
+
+error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds
+  --> $DIR/issue-105227.rs:21:5
+   |
+LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) ->
+   |                    ---- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here
+...
+LL |     (v0.chars().chain(v1.chars()), v2)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b`
+   |
+LL ~ fn chars2<'b>(v0 : &'b str, v1 : &'b str, v2 : &'b str) ->
+LL |
+LL ~     (impl Iterator<Item = char> + 'b , &'b str)
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0700`.
index 000ab6492bb96d6f8d0d04363e424557f7244e0c..4bec3b3415bbc075419ff48d377d651f3ac38a52 100644 (file)
@@ -5,7 +5,7 @@ fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next()
 fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
 //~^ ERROR missing lifetime specifier [E0106]
 //~| ERROR mismatched types
-//~| ERROR this function takes 1 argument but 0 arguments were supplied
+//~| ERROR function takes 1 argument but 0 arguments were supplied
 
 fn parse_type_3() -> &str { unimplemented!() }
 //~^ ERROR missing lifetime specifier [E0106]
index a909c5fa82351ddb2d59dfc4aaf49b5cfc032b8b..cc2447b1877500969643db39e02dd8cec7dae309 100644 (file)
@@ -16,10 +16,13 @@ LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
    |
-LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
-   |                        - help: consider changing this to be mutable: `mut y`
 LL |   y.push(z);
    |   ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn foo(x:fn(&u8, &u8), mut y: Vec<&u8>, z: &u8) {
+   |                        +++
 
 error: aborting due to 2 previous errors
 
index d85ea6529f628e08ea4272e961a378d99a8315bb..2ba5afa808d734af4f66474b92e25d291d6f62b3 100644 (file)
@@ -16,10 +16,13 @@ LL | fn foo<'a>(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&'a u8>, z: &'a u8) {
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
    |
-LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
-   |                                  - help: consider changing this to be mutable: `mut y`
 LL |   y.push(z);
    |   ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , mut y: Vec<&u8>, z: &u8) {
+   |                                  +++
 
 error: aborting due to 2 previous errors
 
index 3040a8512ce1d9b9fbf050796590fb78de9b45d8..9c61d5a0c25e1a6320bf29fe9fcf2d4dad34e982 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
 LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
    |
-   = note: expected `fn(&'1 i32, &'a i32) -> &'a i32`
-              found `fn(&'1 i32, &'1 i32) -> &'1 i32`
+   = note: expected signature `fn(&'1 i32, &'a i32) -> &'a i32`
+              found signature `fn(&'1 i32, &'1 i32) -> &'1 i32`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index 428b8f14b6fcd0e25f266889059cf744b532e9fe..20159e14407201567205320c515ef90a716120b0 100644 (file)
@@ -39,7 +39,7 @@ LL |     type Bar<'b>
 help: add missing lifetime argument
    |
 LL | type C<'a, 'b> = <A<'a> as Trait>::Bar<'a>;
-   |                                    ~~~~~~~
+   |                                       ++++
 
 error: aborting due to 3 previous errors
 
index 72118275774d14b4d82747c4cb03297c3e89d54c..47ab613bec21c1b5f0e64522a27a2f085ca0e2f2 100644 (file)
@@ -4,7 +4,7 @@ warning: unused return value of `Box::<T>::from_raw` that must be used
 LL |     Box::from_raw(ptr);
    |     ^^^^^^^^^^^^^^^^^^
    |
-   = note: call `drop(from_raw(ptr))` if you intend to drop the `Box`
+   = note: call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`
 note: the lint level is defined here
   --> $DIR/must-use-box-from-raw.rs:5:9
    |
diff --git a/src/test/ui/lint/unused_braces_macro.rs b/src/test/ui/lint/unused_braces_macro.rs
new file mode 100644 (file)
index 0000000..bfee953
--- /dev/null
@@ -0,0 +1,6 @@
+// build-pass
+pub fn foo<const BAR: bool> () {}
+
+fn main() {
+    foo::<{cfg!(feature = "foo")}>();
+}
diff --git a/src/test/ui/macros/best-failure.rs b/src/test/ui/macros/best-failure.rs
new file mode 100644 (file)
index 0000000..bbdd465
--- /dev/null
@@ -0,0 +1,11 @@
+macro_rules! number {
+    (neg false, $self:ident) => { $self };
+    ($signed:tt => $ty:ty;) => {
+        number!(neg $signed, $self);
+        //~^ ERROR no rules expected the token `$`
+    };
+}
+
+number! { false => u8; }
+
+fn main() {}
diff --git a/src/test/ui/macros/best-failure.stderr b/src/test/ui/macros/best-failure.stderr
new file mode 100644 (file)
index 0000000..a52fc5e
--- /dev/null
@@ -0,0 +1,21 @@
+error: no rules expected the token `$`
+  --> $DIR/best-failure.rs:4:30
+   |
+LL | macro_rules! number {
+   | ------------------- when calling this macro
+...
+LL |         number!(neg $signed, $self);
+   |                              ^^^^^ no rules expected this token in macro call
+...
+LL | number! { false => u8; }
+   | ------------------------ in this macro invocation
+   |
+note: while trying to match meta-variable `$self:ident`
+  --> $DIR/best-failure.rs:2:17
+   |
+LL |     (neg false, $self:ident) => { $self };
+   |                 ^^^^^^^^^^^
+   = note: this error originates in the macro `number` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
index ff5236dc949b2f09bf471bc0a195889031ed9257..7971c2ab2b9b285357c957b1bd93d64ee04ce5c8 100644 (file)
@@ -8,7 +8,7 @@ LL |     println!("%.*3$s %s!\n", "Hello,", "World", 4);
    |              |               argument never used
    |              multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{:.2$} {}!\n", "Hello,", "World", 4);
@@ -22,7 +22,7 @@ LL |     println!("%1$*2$.*3$f", 123.456);
    |               |
    |               help: format specifiers use curly braces: `{0:1$.2$}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:6:7
@@ -37,7 +37,7 @@ LL | | "###, "Hello,", "World", 4);
    | |____|  argument never used
    |      multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL ~     println!(r###"{:.2$}
@@ -60,7 +60,7 @@ LL |     println!("Hi there, $NAME.", NAME="Tim");
    |                         |
    |                         help: format specifiers use curly braces: `{NAME}`
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:15:32
@@ -72,7 +72,7 @@ LL |     println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
    |              |                 argument never used
    |              multiple missing formatting specifiers
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
index 7423c7b7c8b4736bfcc2860dd92c94b4ffa02b3d..fad87fa2aeea8e4af81c4a66092fdc716811bd34 100644 (file)
@@ -44,7 +44,7 @@ LL |        "things"
 LL |              , UNUSED="args");
    |                       ^^^^^^ named argument never used
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to 4 previous errors
 
index 8d70faa494dbe413916d4f1ba964448cd49b4ec4..8807279c27f93577096448ff5711f26cd1c8241e 100644 (file)
@@ -11,6 +11,8 @@ error: integer literal is too large
    |
 LL |     concat_bytes!(888888888888888888888888888888888888888);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/macros/issue-10536.rs b/src/test/ui/macros/issue-10536.rs
new file mode 100644 (file)
index 0000000..f536d8f
--- /dev/null
@@ -0,0 +1,19 @@
+// We only want to assert that this doesn't ICE, we don't particularly care
+// about whether it nor it fails to compile.
+
+macro_rules! foo{
+    () => {{
+        macro_rules! bar{() => (())}
+        1
+    }}
+}
+
+pub fn main() {
+    foo!();
+
+    assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
+
+    // regardless of whether nested macro_rules works, the following should at
+    // least throw a conventional error.
+    assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
+}
diff --git a/src/test/ui/macros/issue-10536.stderr b/src/test/ui/macros/issue-10536.stderr
new file mode 100644 (file)
index 0000000..cc04844
--- /dev/null
@@ -0,0 +1,14 @@
+error: expected one of `(`, `[`, or `{`, found `two`
+  --> $DIR/issue-10536.rs:14:19
+   |
+LL |     assert!({one! two()});
+   |                   ^^^ expected one of `(`, `[`, or `{`
+
+error: expected one of `(`, `[`, or `{`, found `two`
+  --> $DIR/issue-10536.rs:18:19
+   |
+LL |     assert!({one! two});
+   |                   ^^^ expected one of `(`, `[`, or `{`
+
+error: aborting due to 2 previous errors
+
index d2d66c81198ec71d429632c4ebb0d3e690cf7f86..5359f68cd5517637140140913258401dba6cfed0 100644 (file)
@@ -10,7 +10,7 @@ note: format specifiers use curly braces, and the conversion specifier `
    |
 LL | pub fn main() { println!("🦀%%%", 0) }
    |                               ^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
index ce3424a8b15f07f8eb09aa870f29cdeb6e19c03a..e57347b362dd4faaea384624031cca90310ad816 100644 (file)
@@ -1,8 +1,6 @@
 error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
   --> $DIR/span-covering-argument-1.rs:5:14
    |
-LL |             let $s = 0;
-   |                 -- help: consider changing this to be mutable: `mut foo`
 LL |             *&mut $s = 0;
    |              ^^^^^^^ cannot borrow as mutable
 ...
@@ -10,6 +8,10 @@ LL |     bad!(foo whatever);
    |     ------------------ in this macro invocation
    |
    = note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider changing this to be mutable
+   |
+LL |             let mut $s = 0;
+   |                 +++
 
 error: aborting due to previous error
 
index bc0d4488162b94dc519a586ee99a60db3815a8c1..5cd217df6fc2ff91c814e5c6abb980571141b802 100644 (file)
@@ -801,7 +801,7 @@ fn test_ty() {
     assert_eq!(stringify_ty!(*const T), "*const T");
     assert_eq!(stringify_ty!(*mut T), "*mut T");
 
-    // TyKind::Rptr
+    // TyKind::Ref
     assert_eq!(stringify_ty!(&T), "&T");
     assert_eq!(stringify_ty!(&mut T), "&mut T");
     assert_eq!(stringify_ty!(&'a T), "&'a T");
diff --git a/src/test/ui/match/single-line.rs b/src/test/ui/match/single-line.rs
new file mode 100644 (file)
index 0000000..0f69d08
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    let _ = match Some(42) { Some(x) => x, None => "" }; //~ ERROR E0308
+}
diff --git a/src/test/ui/match/single-line.stderr b/src/test/ui/match/single-line.stderr
new file mode 100644 (file)
index 0000000..ec3b76e
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/single-line.rs:2:52
+   |
+LL |     let _ = match Some(42) { Some(x) => x, None => "" };
+   |             --------------              -          ^^ expected integer, found `&str`
+   |             |                           |
+   |             |                           this is found to be of type `{integer}`
+   |             `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 98b7a8d0d04ebab915d60547d001faa6a505f39a..d7005065813a854823d8b3935b1355f2a571f0f3 100644 (file)
@@ -6,7 +6,8 @@
 
 trait Bar {
     fn f(&self) {
-        self.g(); //~ ERROR the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
+        // issue #105788
+        self.g(); //~ ERROR no method named `g` found for reference `&Self` in the current scope
     }
 }
 
index fb2bdf47de7e540022b78cba209412110fe780f7..7696642548dfe8c5bb28c5b7dbb48b1946c7da51 100644 (file)
@@ -6,21 +6,11 @@ LL | auto trait Foo {
 LL |     fn g(&self);
    |     ---^-------- help: remove these associated items
 
-error[E0599]: the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
-  --> $DIR/issue-105732.rs:9:14
+error[E0599]: no method named `g` found for reference `&Self` in the current scope
+  --> $DIR/issue-105732.rs:10:14
    |
 LL |         self.g();
-   |              ^
-   |
-   = note: the following trait bounds were not satisfied:
-           `Self: Foo`
-           which is required by `&Self: Foo`
-           `&Self: Foo`
-   = help: items from traits can only be used if the type parameter is bounded by the trait
-help: the following trait defines an item `g`, perhaps you need to add a supertrait for it:
-   |
-LL | trait Bar: Foo {
-   |          +++++
+   |              ^ help: there is a method with a similar name: `f`
 
 error: aborting due to 2 previous errors
 
index aec968d7c44f45538a9c05e5e35997ea7a1ffcaf..3e73b950a14e0af982857231d4c358519371dbc1 100644 (file)
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
 LL |         1.query::<dyn ToString>("")
    |           --------------------- ^^ expected trait object `dyn ToString`, found `&str`
    |           |
-   |           arguments to this function are incorrect
+   |           arguments to this method are incorrect
    |
    = note: expected trait object `dyn ToString`
                  found reference `&'static str`
index 79cdc41959a74375248dbeb794c46084e2d5ecbc..fbecaf9b971ffd0f5d18e0018da70943daabde85 100644 (file)
@@ -69,8 +69,7 @@ fn main() {
     //~^ ERROR `usize` is not an iterator
 
     let _res: i32 = ..6.take(2).sum();
-    //~^ can't call method `take` on ambiguous numeric type
-    //~| ERROR mismatched types [E0308]
+    //~^ ERROR can't call method `take` on ambiguous numeric type
     //~| HELP you must specify a concrete type for this numeric value
     // Won't suggest because `RangeTo` dest not implemented `take`
 }
index 8d7b32e025a0864cfb60454c6eb0e2f3b3737de9..4d3c086ff6e8c48747b7a52b115c01c0241b6f02 100644 (file)
@@ -184,18 +184,7 @@ help: you must specify a concrete type for this numeric value, like `i32`
 LL |     let _res: i32 = ..6_i32.take(2).sum();
    |                       ~~~~~
 
-error[E0308]: mismatched types
-  --> $DIR/issue-90315.rs:71:21
-   |
-LL |     let _res: i32 = ..6.take(2).sum();
-   |               ---   ^^^^^^^^^^^^^^^^^ expected `i32`, found struct `RangeTo`
-   |               |
-   |               expected due to this
-   |
-   = note: expected type `i32`
-            found struct `RangeTo<_>`
-
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0308, E0599, E0689.
 For more information about an error, try `rustc --explain E0308`.
index d53ef445afc1bcf06174bf700cb2098ae2a7ac31..4807a956aa2366550daaa727f6250157b93b3905 100644 (file)
@@ -10,13 +10,13 @@ fn three<T>(self, _: T, _: T, _: T) -> Foo { self }
 
 fn main() {
     let x = Foo;
-    x.zero(0)   //~ ERROR this function takes 0 arguments but 1 argument was supplied
-     .one()     //~ ERROR this function takes 1 argument but 0 arguments were supplied
-     .two(0);   //~ ERROR this function takes 2 arguments but 1 argument was supplied
+    x.zero(0)   //~ ERROR this method takes 0 arguments but 1 argument was supplied
+     .one()     //~ ERROR this method takes 1 argument but 0 arguments were supplied
+     .two(0);   //~ ERROR this method takes 2 arguments but 1 argument was supplied
 
     let y = Foo;
     y.zero()
      .take()    //~ ERROR not an iterator
      .one(0);
-    y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
+    y.three::<usize>(); //~ ERROR this method takes 3 arguments but 0 arguments were supplied
 }
index 3f4e647491eb7390efc4ba288ba0a788b0bd2484..81269b73b9a751bbd66155e80b620b66227633c3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 0 arguments but 1 argument was supplied
+error[E0061]: this method takes 0 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:13:7
    |
 LL |     x.zero(0)
@@ -14,7 +14,7 @@ help: remove the extra argument
 LL |     x.zero()
    |           ~~
 
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:14:7
    |
 LL |      .one()
@@ -30,7 +30,7 @@ help: provide the argument
 LL |      .one(/* isize */)
    |          ~~~~~~~~~~~~~
 
-error[E0061]: this function takes 2 arguments but 1 argument was supplied
+error[E0061]: this method takes 2 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:15:7
    |
 LL |      .two(0);
@@ -67,7 +67,7 @@ note: the trait `Iterator` must be implemented
    = note: the following trait defines an item `take`, perhaps you need to implement it:
            candidate #1: `Iterator`
 
-error[E0061]: this function takes 3 arguments but 0 arguments were supplied
+error[E0061]: this method takes 3 arguments but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:21:7
    |
 LL |     y.three::<usize>();
index 54b41926451454ad50712753b435736fe2cecc38..154f2fcbee0ffea76fb8fa80cd2ab48fb977eca8 100644 (file)
@@ -12,8 +12,8 @@ note: type in trait
    |
 LL |     fn foo(x: u16);
    |               ^^^
-   = note: expected fn pointer `fn(u16)`
-              found fn pointer `fn(i16)`
+   = note: expected signature `fn(u16)`
+              found signature `fn(i16)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/E0053.rs:11:12
@@ -29,8 +29,8 @@ note: type in trait
    |
 LL |     fn bar(&self);
    |            ^^^^^
-   = note: expected fn pointer `fn(&Bar)`
-              found fn pointer `fn(&mut Bar)`
+   = note: expected signature `fn(&Bar)`
+              found signature `fn(&mut Bar)`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/issue-106182.fixed b/src/test/ui/mismatched_types/issue-106182.fixed
new file mode 100644 (file)
index 0000000..b8ddebf
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+struct _S(u32, Vec<i32>);
+
+fn _foo(x: &_S) {
+    match x {
+        _S(mut _y, _v) => {
+        //~^ ERROR mismatched types [E0308]
+        }
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/mismatched_types/issue-106182.rs b/src/test/ui/mismatched_types/issue-106182.rs
new file mode 100644 (file)
index 0000000..6eb6df1
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+struct _S(u32, Vec<i32>);
+
+fn _foo(x: &_S) {
+    match x {
+        _S(& (mut _y), _v) => {
+        //~^ ERROR mismatched types [E0308]
+        }
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/mismatched_types/issue-106182.stderr b/src/test/ui/mismatched_types/issue-106182.stderr
new file mode 100644 (file)
index 0000000..ac3ab8e
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-106182.rs:7:12
+   |
+LL |     match x {
+   |           - this expression has type `&_S`
+LL |         _S(& (mut _y), _v) => {
+   |            ^^^^^^^^^^ expected `u32`, found reference
+   |
+   = note:   expected type `u32`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |         _S(mut _y, _v) => {
+   |            ~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index b75c7a99fdd334c98fc8d956c9310233a24fc7d0..9ddea16294450b38afc98f196a1c780caf3d8661 100644 (file)
@@ -18,8 +18,8 @@ LL |     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
    |
    = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
    |
-   = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
-              found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+   = note: expected signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+              found signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index 2a2c23c94212f17f434c0e287e70c28ee2f845f2..88416ba4bb6dc88a9c672999352019e84af6adaa 100644 (file)
@@ -7,8 +7,8 @@ LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
 LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
    |
-   = note: expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
-              found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
+   = note: expected signature `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
+              found signature `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/issue-75361-mismatched-impl.rs:12:55
    |
index 232cd2ba88cc27cbabb328a9a64d0cb6ad5f0e15..5b1804d825d824773d8823fb46c0958c234b326c 100644 (file)
@@ -33,9 +33,9 @@ fn main() {
     let ans = s("what");
     //~^ ERROR mismatched types
     let ans = s();
-    //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+    //~^ ERROR function takes 1 argument but 0 arguments were supplied
     let ans = s("burma", "shave");
-    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~^ ERROR function takes 1 argument but 2 arguments were supplied
 
     F("");
     //~^ ERROR mismatched types
index d9501a9bbc61e3fa75640a7a0e2b7913c2d63e13..63eaa3930b1c3468f66ab51308c8562563c3cf51 100644 (file)
@@ -336,9 +336,8 @@ LL |         let S(&mut _b) = S(0);
    |               ^^^^^^^
 help: consider removing `&mut` from the pattern
    |
-LL -         let S(&mut _b) = S(0);
-LL +         let S(_b) = S(0);
-   |
+LL |         let S(_b) = S(0);
+   |               ~~
 
 error[E0308]: mismatched types
   --> $DIR/ref-pat-suggestions.rs:31:14
index 6b2ba53daa0822947e705aefa3d453e96a51a8c5..6e7bf5eb46d92a921b4d1bcc41f881f363697f4d 100644 (file)
@@ -12,8 +12,8 @@ note: type in trait
    |
 LL |     fn foo(x: u16);
    |               ^^^
-   = note: expected fn pointer `fn(u16)`
-              found fn pointer `fn(i16)`
+   = note: expected signature `fn(u16)`
+              found signature `fn(i16)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/trait-impl-fn-incompatibility.rs:10:28
@@ -29,8 +29,8 @@ note: type in trait
    |
 LL |     fn bar(&mut self, bar: &mut Bar);
    |                            ^^^^^^^^
-   = note: expected fn pointer `fn(&mut Bar, &mut Bar)`
-              found fn pointer `fn(&mut Bar, &Bar)`
+   = note: expected signature `fn(&mut Bar, &mut Bar)`
+              found signature `fn(&mut Bar, &Bar)`
 
 error: aborting due to 2 previous errors
 
index b3f95ee192a565e85a6bc7647068168fd46e203f..7f69e5dcfb784db1ea80cf0b567fe483007f5bc6 100644 (file)
@@ -9,6 +9,10 @@ LL |     val.0;
 note: `into_iter` takes ownership of the receiver `self`, which moves `val.0`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: move occurs because `val.0` has type `Vec<bool>`, which does not implement the `Copy` trait
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |     val.0.clone().into_iter().next();
+   |           ++++++++
 
 error[E0382]: use of moved value: `foo`
   --> $DIR/move-fn-self-receiver.rs:34:5
@@ -93,10 +97,10 @@ note: `Foo::use_rc_self` takes ownership of the receiver `self`, which moves `rc
    |
 LL |     fn use_rc_self(self: Rc<Self>) {}
    |                    ^^^^
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
 LL |     rc_foo.clone().use_rc_self();
-   |           ++++++++
+   |            ++++++++
 
 error[E0382]: use of moved value: `foo_add`
   --> $DIR/move-fn-self-receiver.rs:59:5
@@ -136,10 +140,10 @@ LL |     for _val in explicit_into_iter.into_iter() {}
 LL |     explicit_into_iter;
    |     ^^^^^^^^^^^^^^^^^^ value used here after move
    |
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
 LL |     for _val in explicit_into_iter.clone().into_iter() {}
-   |                                   ++++++++
+   |                                    ++++++++
 
 error[E0382]: use of moved value: `container`
   --> $DIR/move-fn-self-receiver.rs:71:5
index 0b1a623a01345d75294e7bbe31faf28963421782..a28f324aafac9ab17f0719b627b20ebedd96a0aa 100644 (file)
@@ -10,10 +10,10 @@ LL |     touch(&x[0]);
    |
 note: `into_iter` takes ownership of the receiver `self`, which moves `x`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
 LL |     consume(x.clone().into_iter().next().unwrap());
-   |              ++++++++
+   |               ++++++++
 
 error: aborting due to previous error
 
index ae76889f104c89a80910e73028a8675818094e8d..ab7c27456882fdbcaaf79ba1b686a0ce7da46485 100644 (file)
@@ -162,10 +162,10 @@ LL |     touch(&x);
    |
 note: `into_iter` takes ownership of the receiver `self`, which moves `x`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
 LL |     let _y = x.clone().into_iter().next().unwrap();
-   |               ++++++++
+   |                ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:83:11
@@ -179,10 +179,10 @@ LL |     touch(&x);
    |
 note: `into_iter` takes ownership of the receiver `self`, which moves `x`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
-help: consider cloning the value if the performance cost is acceptable
+help: you can `clone` the value and consume it, but this might not be your desired behavior
    |
 LL |     let _y = [x.clone().into_iter().next().unwrap(); 1];
-   |                ++++++++
+   |                 ++++++++
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/moves/pin-mut-reborrow.fixed b/src/test/ui/moves/pin-mut-reborrow.fixed
new file mode 100644 (file)
index 0000000..e808186
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn foo(self: Pin<&mut Self>) {}
+}
+
+fn main() {
+    let mut foo = Foo;
+    let mut foo = Pin::new(&mut foo);
+    foo.as_mut().foo();
+    foo.foo(); //~ ERROR use of moved value
+}
diff --git a/src/test/ui/moves/pin-mut-reborrow.rs b/src/test/ui/moves/pin-mut-reborrow.rs
new file mode 100644 (file)
index 0000000..fee6236
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn foo(self: Pin<&mut Self>) {}
+}
+
+fn main() {
+    let mut foo = Foo;
+    let mut foo = Pin::new(&mut foo);
+    foo.foo();
+    foo.foo(); //~ ERROR use of moved value
+}
diff --git a/src/test/ui/moves/pin-mut-reborrow.stderr b/src/test/ui/moves/pin-mut-reborrow.stderr
new file mode 100644 (file)
index 0000000..16fa4ba
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0382]: use of moved value: `foo`
+  --> $DIR/pin-mut-reborrow.rs:14:5
+   |
+LL |     let mut foo = Pin::new(&mut foo);
+   |         ------- move occurs because `foo` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
+LL |     foo.foo();
+   |         ----- `foo` moved due to this method call
+LL |     foo.foo();
+   |     ^^^ value used here after move
+   |
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `foo`
+  --> $DIR/pin-mut-reborrow.rs:7:12
+   |
+LL |     fn foo(self: Pin<&mut Self>) {}
+   |            ^^^^
+help: consider reborrowing the `Pin` instead of moving it
+   |
+LL |     foo.as_mut().foo();
+   |         +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/moves/suggest-clone.fixed b/src/test/ui/moves/suggest-clone.fixed
new file mode 100644 (file)
index 0000000..204bfdb
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+
+#[derive(Clone)]
+struct Foo;
+impl Foo {
+    fn foo(self) {}
+}
+fn main() {
+    let foo = &Foo;
+    foo.clone().foo(); //~ ERROR cannot move out
+}
diff --git a/src/test/ui/moves/suggest-clone.rs b/src/test/ui/moves/suggest-clone.rs
new file mode 100644 (file)
index 0000000..25dd9f0
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+
+#[derive(Clone)]
+struct Foo;
+impl Foo {
+    fn foo(self) {}
+}
+fn main() {
+    let foo = &Foo;
+    foo.foo(); //~ ERROR cannot move out
+}
diff --git a/src/test/ui/moves/suggest-clone.stderr b/src/test/ui/moves/suggest-clone.stderr
new file mode 100644 (file)
index 0000000..cbb3dfe
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0507]: cannot move out of `*foo` which is behind a shared reference
+  --> $DIR/suggest-clone.rs:10:5
+   |
+LL |     foo.foo();
+   |     ^^^^-----
+   |     |   |
+   |     |   `*foo` moved due to this method call
+   |     move occurs because `*foo` has type `Foo`, which does not implement the `Copy` trait
+   |
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
+  --> $DIR/suggest-clone.rs:6:12
+   |
+LL |     fn foo(self) {}
+   |            ^^^^
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |     foo.clone().foo();
+   |         ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
index 3104b20aca4e6428bdb75035eed5e9ef7681934e..8c269d1e727643e96a43a28f115014bfa30a1c00 100644 (file)
@@ -8,7 +8,7 @@ fn mutate(&mut self) {
 
 fn func(arg: S) {
     //~^ HELP consider changing this to be mutable
-    //~| SUGGESTION mut arg
+    //~| SUGGESTION mut
     arg.mutate();
     //~^ ERROR cannot borrow `arg` as mutable, as it is not declared as mutable
 }
@@ -16,7 +16,7 @@ fn func(arg: S) {
 fn main() {
     let local = S;
     //~^ HELP consider changing this to be mutable
-    //~| SUGGESTION mut local
+    //~| SUGGESTION mut
     local.mutate();
     //~^ ERROR cannot borrow `local` as mutable, as it is not declared as mutable
 }
index cba284550b95a3cb818dd5ad8c693a3006c78669..d89c8b41304af7ed3a7d370da726771e46e954d6 100644 (file)
@@ -1,20 +1,24 @@
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/mut-suggestion.rs:12:5
    |
-LL | fn func(arg: S) {
-   |         --- help: consider changing this to be mutable: `mut arg`
-...
 LL |     arg.mutate();
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn func(mut arg: S) {
+   |         +++
 
 error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable
   --> $DIR/mut-suggestion.rs:20:5
    |
-LL |     let local = S;
-   |         ----- help: consider changing this to be mutable: `mut local`
-...
 LL |     local.mutate();
    |     ^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut local = S;
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 5a4e31947f2b2e889a1ceee9b40625fe3c4a0270..c53c6ea302c6716feb0f9ad40a3f62df4a29e5c4 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `self.how_hungry`, which is behind a `&` reference
   --> $DIR/mutable-class-fields-2.rs:9:5
    |
-LL |   pub fn eat(&self) {
-   |              ----- help: consider changing this to be a mutable reference: `&mut self`
 LL |     self.how_hungry -= 5;
    |     ^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |   pub fn eat(&mut self) {
+   |              ~~~~~~~~~
 
 error: aborting due to previous error
 
index 40a0dc9b29c238223d00e8aab5b98582d59eef48..1d731be8a855db5d550d23c0bbab88869abdbbc1 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable
   --> $DIR/mutable-class-fields.rs:15:3
    |
-LL |   let nyan : Cat = cat(52, 99);
-   |       ---- help: consider changing this to be mutable: `mut nyan`
 LL |   nyan.how_hungry = 0;
    |   ^^^^^^^^^^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |   let mut nyan : Cat = cat(52, 99);
+   |       +++
 
 error: aborting due to previous error
 
index 25f47f5b6f6c93a0ec55953f6147a0e1ce4753aa..260c16c17d4a2b8c662abc1f27c47be07072b727 100644 (file)
@@ -16,16 +16,6 @@ impl Trait for &'static () {
 
 fn main() {
     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-    //~^ ERROR lifetime may not live long enough
-    //~| ERROR higher-ranked subtype error
-    //~| ERROR higher-ranked subtype error
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
-    //~| ERROR implementation of `Trait` is not general enough
+    //~^ ERROR implementation of `Trait` is not general enough
     //~| ERROR implementation of `Trait` is not general enough
 }
index dbd5dabd1daccbd15849ffc2d04fb698642b426f..46dba0064339ff783c19d7229a80afe878565d53 100644 (file)
@@ -1,51 +1,3 @@
-error: lifetime may not live long enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^-^
-   |                                                ||
-   |                                                |has type `<&'1 () as Trait>::Ty`
-   |                                                requires that `'1` must outlive `'static`
-
-error: higher-ranked subtype error
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^
-
-error: higher-ranked subtype error
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^
-
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
 error: implementation of `Trait` is not general enough
   --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
    |
@@ -64,41 +16,5 @@ LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
    = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
    = note: ...but `Trait` is actually implemented for the type `&'static ()`
 
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: implementation of `Trait` is not general enough
-  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
-   |
-LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
-   |                                                ^^^^^^ implementation of `Trait` is not general enough
-   |
-   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
-   = note: ...but `Trait` is actually implemented for the type `&'static ()`
-
-error: aborting due to 12 previous errors
+error: aborting due to 2 previous errors
 
index 7253d35ed2d4fe9e6c04157057e19c3821a0f2a3..ccfc8937fd72e531002dcf3b673628348a917dc7 100644 (file)
@@ -5,6 +5,8 @@
 // See further discussion on rust-lang/rust#24535,
 // rust-lang/rfcs#1006, and rust-lang/rfcs#107
 
+#![feature(if_let_guard)]
+
 fn main() {
     rust_issue_24535();
     rfcs_issue_1006_1();
@@ -23,6 +25,12 @@ fn compare(a: &u8, b: &mut u8) -> bool {
         3 if compare(&a, &mut 3) => (),
         _ => panic!("nope"),
     }
+
+    match a {
+        0 => panic!("nope"),
+        3 if let true = compare(&a, &mut 3) => (),
+        _ => panic!("nope"),
+    }
 }
 
 fn rfcs_issue_1006_1() {
index 4109c10e2e46bf6bb9a17a05ca048b65f4b1c641..85feda5824b408420932a7cd33e64f4d9075db59 100644 (file)
@@ -7,6 +7,8 @@
 // reaches the panic code when executed, despite the compiler warning
 // about that match arm being unreachable.
 
+#![feature(if_let_guard)]
+
 fn main() {
     let b = &mut true;
     match b {
@@ -17,4 +19,16 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let b = &mut true;
+    match b {
+        //~^ ERROR use of moved value: `b` [E0382]
+        &mut false => {}
+        _ if let Some(()) = {
+            (|| { let bar = b; *bar = false; })();
+            None
+        } => {}
+        &mut true => {}
+        _ => {}
+    }
 }
index 9be1a9279992b813037fe28e38d492df4694d09f..ae7978004576b886be6cdad5b065fe2d5d307f2b 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `b`
-  --> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
    |
 LL |     let b = &mut true;
    |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
@@ -11,6 +11,19 @@ LL |         _ if { (|| { let bar = b; *bar = false; })();
    |                 |
    |                 value moved into closure here
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `b`
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+   |
+LL |     let b = &mut true;
+   |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL |     match b {
+   |     ^^^^^^^ value used here after move
+...
+LL |             (|| { let bar = b; *bar = false; })();
+   |              --             - variable moved due to use in closure
+   |              |
+   |              value moved into closure here
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index afa0ba780de46e1826d713ab3c981e8ad244d66b..833ca8afd618e1e88815baa82589a87128bceb0f 100644 (file)
@@ -2,6 +2,8 @@
 // mutable borrows in match guards by hiding the mutable borrow in a
 // guard behind a move (of the ref mut pattern id) within a closure.
 
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,12 @@ fn main() {
         //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+        //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+        Some(s) => std::process::exit(*s),
+    }
 }
index a0d32616f83b74f2dad691636171476b1d40cc59..45119018d4e60570243a455dc0129f584db68403 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
    |
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+   |
+LL |             if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+   |                                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                                  |
+   |                                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 395c7d214d0ce03b356b6b36b59472ab71e49df6..4f41fc23fc34be2632abef60f9734e03a71b39b4 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,15 @@ fn main() {
         Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
         _ => println!("Here is some supposedly unreachable code."),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = {
+                (|| { let bar = foo; bar.take() })();
+                //~^ ERROR cannot move out of `foo` in pattern guard
+                None
+            } => {},
+        Some(_) => {},
+    }
 }
index c4ce7e62fda82bc24bb45d8b3f90b7afb8f9664b..1ba696593afffe4adafbac72bb0e1055fa4b4d71 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-mutation-in-guard.rs:6:18
+  --> $DIR/issue-27282-mutation-in-guard.rs:8:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
    |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |                 (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+   |
+LL |                 (|| { let bar = foo; bar.take() })();
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
+   |                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 82d8b9e9ed977d9b28f558d4b894a4ecd9bba6aa..ac06b2b01028f925fea29944249ebd79cf2a71db 100644 (file)
@@ -3,7 +3,9 @@
 // It reborrows instead of moving the `ref mut` pattern borrow. This
 // means that our conservative check for mutation in guards will
 // reject it. But I want to make sure that we continue to reject it
-// (under NLL) even when that conservaive check goes away.
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
 
 fn main() {
     let mut b = &mut true;
@@ -15,4 +17,14 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let mut b = &mut true;
+    match b {
+        &mut false => {},
+        ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+        //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+                             None } => { &mut *r; },
+        &mut true => {},
+        _ => {},
+    }
 }
index 48433432de1bd7ccccf307f0230a603257778528..5eb7a25bf9f507357225d7cf9677648f6af26105 100644 (file)
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
-  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |                         ^^                  -- mutable borrow occurs due to use of `r` in closure
@@ -8,6 +8,16 @@ LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
-error: aborting due to previous error
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+   |
+LL |         ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+   |                                        ^^                  -- mutable borrow occurs due to use of `r` in closure
+   |                                        |
+   |                                        cannot borrow as mutable
+   |
+   = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
index a4ee7781753060f0bb8c6fbd7f5227d692f031c0..c780451dfa9355d9a74f2ce326c1b5474fcbcfc6 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `fancy_ref.num`, which is behind a `&` reference
   --> $DIR/issue-47388.rs:8:5
    |
-LL |     let fancy_ref = &(&mut fancy);
-   |                     ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
 LL |     fancy_ref.num = 6;
    |     ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let fancy_ref = &mut (&mut fancy);
+   |                     ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 63ca6ae5c284164a641021957fcc03a54d37b309..27b1f8705ff1c163840726f7b110d80e730b0012 100644 (file)
@@ -30,10 +30,13 @@ LL |         (&mut self).bar();
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
   --> $DIR/issue-51191.rs:13:9
    |
-LL |     fn imm(self) {
-   |            ---- help: consider changing this to be mutable: `mut self`
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn imm(mut self) {
+   |            +++
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
   --> $DIR/issue-51191.rs:22:9
index dcb6f9fec18b6eb94aec31ecd326569227f1674c..03d8acc81886a3f1cc4ce3735554946adbd2ffcf 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference
   --> $DIR/issue-51244.rs:3:5
    |
-LL |     let ref my_ref @ _ = 0;
-   |         ---------- help: consider changing this to be a mutable reference: `ref mut my_ref`
 LL |     *my_ref = 0;
    |     ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let ref mut my_ref @ _ = 0;
+   |         ~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-54189.rs b/src/test/ui/nll/issue-54189.rs
new file mode 100644 (file)
index 0000000..70aecc3
--- /dev/null
@@ -0,0 +1,6 @@
+fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+//~^ ERROR binding for associated type `Output` references lifetime `'r`
+
+fn main() {
+    let f = bug();
+}
diff --git a/src/test/ui/nll/issue-54189.stderr b/src/test/ui/nll/issue-54189.stderr
new file mode 100644 (file)
index 0000000..4787abd
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types
+  --> $DIR/issue-54189.rs:1:35
+   |
+LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+   |                                   ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
index e85e63e52ecc37bbec6731f5b2f1c34078cddf92..31f40d8252ed6a40745dc26e2606729a84cf5a8b 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `*x`, which is behind a `&` reference
   --> $DIR/issue-57989.rs:5:5
    |
-LL | fn f(x: &i32) {
-   |         ---- help: consider changing this to be a mutable reference: `&mut i32`
-LL |     let g = &x;
 LL |     *x = 0;
    |     ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn f(x: &mut i32) {
+   |         ~~~~~~~~
 
 error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/issue-57989.rs:5:5
index 252f7f8ba07cff05e8bbc6f3aed6e2779e001640..1afc7931a6b629732476a78077c816040ba2e477 100644 (file)
@@ -1,6 +1,8 @@
 // Test that we have enough false edges to avoid exposing the exact matching
 // algorithm in borrow checking.
 
+#![feature(if_let_guard)]
+
 fn guard_always_precedes_arm(y: i32) {
     let mut x;
     // x should always be initialized, as the only way to reach the arm is
@@ -9,6 +11,12 @@ fn guard_always_precedes_arm(y: i32) {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
     };
+
+    let mut x;
+    match y {
+        0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+        _ => 2,
+    };
 }
 
 fn guard_may_be_skipped(y: i32) {
@@ -23,6 +31,16 @@ fn guard_may_be_skipped(y: i32) {
         } => 2,
         _ => 3,
     };
+
+    let x;
+    match y {
+        _ if let Some(()) = { x = 2; Some(()) } => 1,
+        _ if let Some(()) = {
+            x; //~ ERROR E0381
+            None
+        } => 2,
+        _ => 3,
+    };
 }
 
 fn guard_may_be_taken(y: bool) {
@@ -37,6 +55,16 @@ fn guard_may_be_taken(y: bool) {
         }
         false => 3,
     };
+
+    let x = String::new();
+    match y {
+        false if let Some(()) = { drop(x); Some(()) } => 1,
+        true => {
+            x; //~ ERROR use of moved value: `x`
+            2
+        }
+        false => 3,
+    };
 }
 
 fn main() {}
index f72ed3af71823de592dba52b3fe33f787507c125..a6261345ceac7bc7fbcd92a666f98d0a506fa2f8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:21:13
+  --> $DIR/match-cfg-fake-edges.rs:29:13
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
@@ -15,8 +15,25 @@ help: consider assigning a value
 LL |     let x = 0;
    |           +++
 
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:39:13
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
+LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
+   |                               ----- binding initialized here in some conditions
+LL |         _ if let Some(()) = {
+LL |             x;
+   |             ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
+
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:35:13
+  --> $DIR/match-cfg-fake-edges.rs:53:13
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -32,7 +49,24 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         false if { drop(x.clone()); true } => 1,
    |                          ++++++++
 
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:63:13
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL |     match y {
+LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
+   |                                        - value moved here
+LL |         true => {
+LL |             x;
+   |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+   |                                         ++++++++
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
index 87dba187ba2c2ed4ba4f343f3c4df8588306403b..ff63cc092734a0211af6825597610f4bd921c42c 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 // Here is arielb1's basic example from rust-lang/rust#27282
 // that AST borrowck is flummoxed by:
 
@@ -10,6 +12,15 @@ fn should_reject_destructive_mutate_in_guard() {
             false } => { },
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(()) = {
+            (|| { let bar = foo; bar.take() })();
+            //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+            None } => { },
+        Some(s) => std::process::exit(*s),
+    }
 }
 
 // Here below is a case that needs to keep working: we only use the
@@ -18,7 +29,13 @@ fn should_reject_destructive_mutate_in_guard() {
 fn allow_mutate_in_arm_body() {
     match Some(&4) {
         None => {},
-        ref mut foo if foo.is_some() && false => { foo.take(); () }
+        ref mut foo if foo.is_some() => { foo.take(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(_) = foo => { foo.take(); () }
         Some(s) => std::process::exit(*s),
     }
 }
@@ -29,7 +46,13 @@ fn allow_mutate_in_arm_body() {
 fn allow_move_into_arm_body() {
     match Some(&4) {
         None => {},
-        mut foo if foo.is_some() && false => { foo.take(); () }
+        mut foo if foo.is_some() => { foo.unwrap(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        mut foo if let Some(_) = foo => { foo.unwrap(); () }
         Some(s) => std::process::exit(*s),
     }
 }
index c0fb5f65382dce4eccdd3be95cecabd71085d28b..fa01d3a6fd1e0092a95e40c270c4f7b681626f97 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/match-guards-always-borrow.rs:8:14
+  --> $DIR/match-guards-always-borrow.rs:10:14
    |
 LL |             (|| { let bar = foo; bar.take() })();
    |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/match-guards-always-borrow.rs:19:14
+   |
+LL |             (|| { let bar = foo; bar.take() })();
+   |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |              |
+   |              move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 81ae19ebf8a7210106c7403635ce3a5e8d9bfa5c..3a9e1654b1c2d985aa491f467ece89f0629ad422 100644 (file)
@@ -5,7 +5,9 @@
 // Test that we don't allow mutating the value being matched on in a way that
 // changes which patterns it matches, until we have chosen an arm.
 
-fn ok_mutation_in_guard(mut q: i32) {
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
     match q {
         // OK, mutation doesn't change which patterns g matches
         _ if { q = 1; false } => (),
@@ -13,7 +15,15 @@ fn ok_mutation_in_guard(mut q: i32) {
     }
 }
 
-fn ok_mutation_in_guard2(mut u: bool) {
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+    match q {
+        // OK, mutation doesn't change which patterns g matches
+        _ if let Some(()) = { q = 1; None } => (),
+        _ => (),
+    }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
     // OK value of u is unused before modification
     match u {
         _ => (),
@@ -25,7 +35,19 @@ fn ok_mutation_in_guard2(mut u: bool) {
     }
 }
 
-fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+    // OK value of u is unused before modification
+    match u {
+        _ => (),
+        _ if let Some(()) = {
+            u = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
     // OK value of u is unused before modification
     match w {
         _ => (),
@@ -37,7 +59,19 @@ fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
     }
 }
 
-fn ok_indirect_mutation_in_guard(mut p: &bool) {
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+    // OK value of u is unused before modification
+    match w {
+        _ => (),
+        _ if let Some(()) = {
+            *w.0 = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
     match *p {
         // OK, mutation doesn't change which patterns s matches
         _ if {
@@ -48,7 +82,18 @@ fn ok_indirect_mutation_in_guard(mut p: &bool) {
     }
 }
 
-fn mutation_invalidates_pattern_in_guard(mut q: bool) {
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+    match *p {
+        // OK, mutation doesn't change which patterns s matches
+        _ if let Some(()) = {
+            p = &true;
+            None
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
     match q {
         // q doesn't match the pattern with the guard by the end of the guard.
         false if {
@@ -59,7 +104,18 @@ fn mutation_invalidates_pattern_in_guard(mut q: bool) {
     }
 }
 
-fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+    match q {
+        // q doesn't match the pattern with the guard by the end of the guard.
+        false if let Some(()) = {
+            q = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
     match r {
         // r matches a previous pattern by the end of the guard.
         true => (),
@@ -71,7 +127,19 @@ fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
     }
 }
 
-fn match_on_borrowed_early_end(mut s: bool) {
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+    match r {
+        // r matches a previous pattern by the end of the guard.
+        true => (),
+        _ if let Some(()) = {
+            r = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
     let h = &mut s;
     // OK value of s is unused before modification.
     match s {
@@ -84,7 +152,20 @@ fn match_on_borrowed_early_end(mut s: bool) {
     }
 }
 
-fn bad_mutation_in_guard(mut t: bool) {
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+    let h = &mut s;
+    // OK value of s is unused before modification.
+    match s {
+        _ if let Some(()) = {
+            *h = !*h;
+            None
+        } => (),
+        true => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
     match t {
         true => (),
         false if {
@@ -95,7 +176,18 @@ fn bad_mutation_in_guard(mut t: bool) {
     }
 }
 
-fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+    match t {
+        true => (),
+        false if let Some(()) = {
+            t = true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
     // Check that nested patterns are checked.
     match x {
         None => (),
@@ -111,7 +203,23 @@ fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
     }
 }
 
-fn bad_mutation_in_guard3(mut t: bool) {
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+    // Check that nested patterns are checked.
+    match x {
+        None => (),
+        Some(None) => (),
+        _ if let Some(()) = {
+            match x {
+                Some(ref mut r) => *r = None, //~ ERROR
+                _ => return,
+            };
+            None
+        } => (),
+        Some(Some(r)) => println!("{}", r),
+    }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
     match t {
         s if {
             t = !t; //~ ERROR
@@ -121,7 +229,17 @@ fn bad_mutation_in_guard3(mut t: bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard(mut y: &bool) {
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+    match t {
+        s if let Some(()) = {
+            t = !t; //~ ERROR
+            None
+        } => (), // What value should `s` have in the arm?
+        _ => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
     match *y {
         true => (),
         false if {
@@ -132,7 +250,18 @@ fn bad_indirect_mutation_in_guard(mut y: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard2(mut z: &bool) {
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+    match *y {
+        true => (),
+        false if let Some(()) = {
+            y = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
     match z {
         &true => (),
         &false if {
@@ -143,8 +272,19 @@ fn bad_indirect_mutation_in_guard2(mut z: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard3(mut a: &bool) {
-    // Same as bad_indirect_mutation_in_guard2, but using match ergonomics
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+    match z {
+        &true => (),
+        &false if let Some(()) = {
+            z = &true; //~ ERROR
+            None
+        } => (),
+        &false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
     match a {
         true => (),
         false if {
@@ -155,7 +295,19 @@ fn bad_indirect_mutation_in_guard3(mut a: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard4(mut b: &bool) {
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+    match a {
+        true => (),
+        false if let Some(()) = {
+            a = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
     match b {
         &_ => (),
         &_ if {
@@ -166,4 +318,15 @@ fn bad_indirect_mutation_in_guard4(mut b: &bool) {
     }
 }
 
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+    match b {
+        &_ => (),
+        &_ if let Some(()) = {
+            b = &true; //~ ERROR
+            None
+        } => (),
+        &b => (),
+    }
+}
+
 fn main() {}
index 48e3a7c6993182bf890740347a800a93b8ff71f3..60b8dee71a8632e2866abc43561c1b0dd36bd25c 100644 (file)
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `q` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:55:13
+  --> $DIR/match-guards-partially-borrow.rs:100:13
    |
 LL |     match q {
    |           - value is immutable in match guard
@@ -7,8 +7,26 @@ LL |     match q {
 LL |             q = true;
    |             ^^^^^^^^ cannot assign
 
+error[E0510]: cannot assign `q` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:111:13
+   |
+LL |     match q {
+   |           - value is immutable in match guard
+...
+LL |             q = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:123:13
+   |
+LL |     match r {
+   |           - value is immutable in match guard
+...
+LL |             r = true;
+   |             ^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `r` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:67:13
+  --> $DIR/match-guards-partially-borrow.rs:135:13
    |
 LL |     match r {
    |           - value is immutable in match guard
@@ -17,7 +35,16 @@ LL |             r = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `t` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:91:13
+  --> $DIR/match-guards-partially-borrow.rs:172:13
+   |
+LL |     match t {
+   |           - value is immutable in match guard
+...
+LL |             t = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:183:13
    |
 LL |     match t {
    |           - value is immutable in match guard
@@ -26,7 +53,16 @@ LL |             t = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x.0` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:105:22
+  --> $DIR/match-guards-partially-borrow.rs:197:22
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |                 Some(ref mut r) => *r = None,
+   |                      ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:213:22
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -35,7 +71,7 @@ LL |                 Some(ref mut r) => *r = None,
    |                      ^^^^^^^^^ cannot mutably borrow
 
 error[E0506]: cannot assign to `t` because it is borrowed
-  --> $DIR/match-guards-partially-borrow.rs:117:13
+  --> $DIR/match-guards-partially-borrow.rs:225:13
    |
 LL |         s if {
    |         - borrow of `t` occurs here
@@ -45,8 +81,28 @@ LL |             false
 LL |         } => (), // What value should `s` have in the arm?
    |         - borrow later used here
 
+error[E0506]: cannot assign to `t` because it is borrowed
+  --> $DIR/match-guards-partially-borrow.rs:235:13
+   |
+LL |         s if let Some(()) = {
+   |         - borrow of `t` occurs here
+LL |             t = !t;
+   |             ^^^^^^ assignment to borrowed `t` occurs here
+LL |             None
+LL |         } => (), // What value should `s` have in the arm?
+   |         - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:246:13
+   |
+LL |     match *y {
+   |           -- value is immutable in match guard
+...
+LL |             y = &true;
+   |             ^^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `y` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:128:13
+  --> $DIR/match-guards-partially-borrow.rs:257:13
    |
 LL |     match *y {
    |           -- value is immutable in match guard
@@ -55,7 +111,16 @@ LL |             y = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `z` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:139:13
+  --> $DIR/match-guards-partially-borrow.rs:268:13
+   |
+LL |     match z {
+   |           - value is immutable in match guard
+...
+LL |             z = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:279:13
    |
 LL |     match z {
    |           - value is immutable in match guard
@@ -64,7 +129,16 @@ LL |             z = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `a` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:151:13
+  --> $DIR/match-guards-partially-borrow.rs:291:13
+   |
+LL |     match a {
+   |           - value is immutable in match guard
+...
+LL |             a = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:303:13
    |
 LL |     match a {
    |           - value is immutable in match guard
@@ -73,7 +147,16 @@ LL |             a = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `b` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:162:13
+  --> $DIR/match-guards-partially-borrow.rs:314:13
+   |
+LL |     match b {
+   |           - value is immutable in match guard
+...
+LL |             b = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:325:13
    |
 LL |     match b {
    |           - value is immutable in match guard
@@ -81,7 +164,7 @@ LL |     match b {
 LL |             b = &true;
    |             ^^^^^^^^^ cannot assign
 
-error: aborting due to 9 previous errors
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0506, E0510.
 For more information about an error, try `rustc --explain E0506`.
index 6abe53127c3fb080cc64083a53995d62ff289312..0fc3670d6c52343f4fee8e87e57d6e6fb46b622a 100644 (file)
@@ -1,8 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
-  --> $DIR/normalization-bounds-error.rs:12:1
+  --> $DIR/normalization-bounds-error.rs:12:31
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'d` as defined here...
   --> $DIR/normalization-bounds-error.rs:12:14
@@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined he
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    |                  ^^
 note: ...so that the types are compatible
-  --> $DIR/normalization-bounds-error.rs:12:1
+  --> $DIR/normalization-bounds-error.rs:12:31
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected `Visitor<'d>`
               found `Visitor<'_>`
 
index a62157f44f53f4f70997f55d9553011fe9364ba3..da3bc20832286aab2f63f8e0e2fc1e6b5e0febd6 100644 (file)
@@ -5,7 +5,7 @@ LL | fn uninit<'a>() {
    |           -- lifetime `'a` defined here
 LL |     return;
 LL |     let x: &'static &'a ();
-   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:11:12
@@ -14,7 +14,7 @@ LL | fn var_type<'a>() {
    |             -- lifetime `'a` defined here
 LL |     return;
 LL |     let x: &'static &'a () = &&();
-   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:15:12
@@ -22,7 +22,7 @@ error: lifetime may not live long enough
 LL | fn uninit_infer<'a>() {
    |                 -- lifetime `'a` defined here
 LL |     let x: &'static &'a _;
-   |            ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:21:12
@@ -31,7 +31,7 @@ LL | fn infer<'a>() {
    |          -- lifetime `'a` defined here
 LL |     return;
 LL |     let x: &'static &'a _ = &&();
-   |            ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:26:12
@@ -40,7 +40,7 @@ LL | fn uninit_no_var<'a>() {
    |                  -- lifetime `'a` defined here
 LL |     return;
 LL |     let _: &'static &'a ();
-   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:31:12
@@ -49,7 +49,7 @@ LL | fn no_var<'a>() {
    |           -- lifetime `'a` defined here
 LL |     return;
 LL |     let _: &'static &'a () = &&();
-   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:36:12
@@ -58,7 +58,7 @@ LL | fn infer_no_var<'a>() {
    |                 -- lifetime `'a` defined here
 LL |     return;
 LL |     let _: &'static &'a _ = &&();
-   |            ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
   --> $DIR/wf-unreachable.rs:49:12
@@ -67,7 +67,7 @@ LL | fn required_substs<'a>() {
    |                    -- lifetime `'a` defined here
 LL |     return;
 LL |     let _: C<'static, 'a, _> = C((), &(), &());
-   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |            ^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: aborting due to 8 previous errors
 
index 14460dea5b5270a03e3e4f69071be2929c477260..5db02c46ec36954a251626317b150f7f490c2096 100644 (file)
@@ -1,5 +1,5 @@
-// check-pass
-// known-bug: #101350
+// Regression test for #101350.
+// check-fail
 
 trait Trait {
     type Ty;
@@ -11,6 +11,7 @@ impl Trait for &'static () {
 
 fn extend<'a>() {
     None::<<&'a () as Trait>::Ty>;
+    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/user-annotations/ascribed-type-wf.stderr b/src/test/ui/nll/user-annotations/ascribed-type-wf.stderr
new file mode 100644 (file)
index 0000000..91e7c6b
--- /dev/null
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/ascribed-type-wf.rs:13:5
+   |
+LL | fn extend<'a>() {
+   |           -- lifetime `'a` defined here
+LL |     None::<<&'a () as Trait>::Ty>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/closure-sig.rs b/src/test/ui/nll/user-annotations/closure-sig.rs
new file mode 100644 (file)
index 0000000..4dbd3fd
--- /dev/null
@@ -0,0 +1,15 @@
+// This test fails if #104478 is fixed before #104477.
+
+// check-pass
+
+struct Printer<'a, 'b>(&'a (), &'b ());
+
+impl Printer<'_, '_> {
+    fn test(self) {
+        let clo = |_: &'_ Self| {};
+        clo(&self);
+        clo(&self);
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-2.rs b/src/test/ui/nll/user-annotations/normalization-2.rs
new file mode 100644 (file)
index 0000000..be23c3b
--- /dev/null
@@ -0,0 +1,152 @@
+// Make sure we honor region constraints when normalizing type annotations.
+
+// check-fail
+
+#![feature(more_qualified_paths)]
+
+trait Trait {
+    type Assoc;
+}
+
+impl<T> Trait for T
+where
+    T: 'static,
+{
+    type Assoc = MyTy<()>;
+}
+
+enum MyTy<T> {
+    Unit,
+    Tuple(),
+    Struct {},
+    Dumb(T),
+}
+
+impl<T> MyTy<T> {
+    const CONST: () = ();
+    fn method<X>() {}
+    fn method2<X>(&self) {}
+}
+
+trait TraitAssoc {
+    const TRAIT_CONST: ();
+    fn trait_method<X>(&self);
+}
+impl<T> TraitAssoc for T {
+    const TRAIT_CONST: () = ();
+    fn trait_method<X>(&self) {}
+}
+
+type Ty<'a> = <&'a () as Trait>::Assoc;
+
+fn test_local<'a>() {
+    let _: Ty<'a> = MyTy::Unit;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_closure_sig<'a, 'b>() {
+    |_: Ty<'a>| {};
+    //~^ ERROR lifetime may not live long enough
+    || -> Option<Ty<'b>> { None };
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+    <Ty<'a>>::method::<Ty<'static>>;
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'static>>::method::<Ty<'b>>;
+    //~^ ERROR lifetime may not live long enough
+
+    <Ty<'c>>::trait_method::<Ty<'static>>;
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'static>>::trait_method::<Ty<'d>>;
+    //~^ ERROR lifetime may not live long enough
+
+    <Ty<'e>>::CONST;
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'f>>::TRAIT_CONST;
+    //~^ ERROR lifetime may not live long enough
+
+    <Ty<'static>>::method::<Ty<'static>>;
+    <Ty<'static>>::trait_method::<Ty<'static>>;
+    <Ty<'static>>::CONST;
+    <Ty<'static>>::TRAIT_CONST;
+
+    MyTy::Unit::<Ty<'g>>;
+    //~^ ERROR lifetime may not live long enough
+    MyTy::<Ty<'h>>::Unit;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_call<'a, 'b, 'c>() {
+    <Ty<'a>>::method::<Ty<'static>>();
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'static>>::method::<Ty<'b>>();
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_variants<'a, 'b, 'c>() {
+    <Ty<'a>>::Struct {};
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'b>>::Tuple();
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'c>>::Unit;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_method_call<'a, 'b>(x: MyTy<()>) {
+    x.method2::<Ty<'a>>();
+    //~^ ERROR lifetime may not live long enough
+    x.trait_method::<Ty<'b>>();
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_struct_path<'a, 'b, 'c, 'd>() {
+    struct Struct<T> { x: Option<T>, }
+
+    trait Project {
+        type Struct;
+        type Enum;
+    }
+    impl<T> Project for T {
+        type Struct = Struct<()>;
+        type Enum = MyTy<()>;
+    }
+
+    // Resolves to enum variant
+    MyTy::<Ty<'a>>::Struct {}; // without SelfTy
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'b> as Project>::Enum::Struct {}; // with SelfTy
+    //~^ ERROR lifetime may not live long enough
+
+    // Resolves to struct and associated type respectively
+    Struct::<Ty<'c>> { x: None, }; // without SelfTy
+    //~^ ERROR lifetime may not live long enough
+    <Ty<'d> as Project>::Struct { x: None, }; // with SelfTy
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+    use MyTy::*;
+    match MyTy::Unit {
+        Struct::<Ty<'a>> {..} => {},
+        //~^ ERROR lifetime may not live long enough
+        Tuple::<Ty<'b>> (..) => {},
+        //~^ ERROR lifetime may not live long enough
+        Unit::<Ty<'c>> => {},
+        //~^ ERROR lifetime may not live long enough
+        Dumb(_) => {},
+    };
+    match MyTy::Unit {
+        <Ty<'d>>::Struct {..} => {},
+        //~^ ERROR lifetime may not live long enough
+        <Ty<'e>>::Tuple (..) => {},
+        //~^ ERROR lifetime may not live long enough
+        <Ty<'f>>::Unit => {},
+        //~^ ERROR lifetime may not live long enough
+        Dumb(_) => {},
+    };
+}
+
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-2.stderr b/src/test/ui/nll/user-annotations/normalization-2.stderr
new file mode 100644 (file)
index 0000000..5299282
--- /dev/null
@@ -0,0 +1,296 @@
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:43:12
+   |
+LL | fn test_local<'a>() {
+   |               -- lifetime `'a` defined here
+LL |     let _: Ty<'a> = MyTy::Unit;
+   |            ^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:48:6
+   |
+LL | fn test_closure_sig<'a, 'b>() {
+   |                     -- lifetime `'a` defined here
+LL |     |_: Ty<'a>| {};
+   |      ^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:50:11
+   |
+LL | fn test_closure_sig<'a, 'b>() {
+   |                         -- lifetime `'b` defined here
+...
+LL |     || -> Option<Ty<'b>> { None };
+   |           ^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:55:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |              -- lifetime `'a` defined here
+LL |     <Ty<'a>>::method::<Ty<'static>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:57:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                  -- lifetime `'b` defined here
+...
+LL |     <Ty<'static>>::method::<Ty<'b>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:60:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                      -- lifetime `'c` defined here
+...
+LL |     <Ty<'c>>::trait_method::<Ty<'static>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:62:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                          -- lifetime `'d` defined here
+...
+LL |     <Ty<'static>>::trait_method::<Ty<'d>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:65:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                              -- lifetime `'e` defined here
+...
+LL |     <Ty<'e>>::CONST;
+   |     ^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:67:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                                  -- lifetime `'f` defined here
+...
+LL |     <Ty<'f>>::TRAIT_CONST;
+   |     ^^^^^^^^^^^^^^^^^^^^^ requires that `'f` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:75:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                                      -- lifetime `'g` defined here
+...
+LL |     MyTy::Unit::<Ty<'g>>;
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'g` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:77:5
+   |
+LL | fn test_path<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>() {
+   |                                          -- lifetime `'h` defined here
+...
+LL |     MyTy::<Ty<'h>>::Unit;
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'h` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+   = help: replace `'c` with `'static`
+   = help: replace `'d` with `'static`
+   = help: replace `'e` with `'static`
+   = help: replace `'f` with `'static`
+   = help: replace `'g` with `'static`
+   = help: replace `'h` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:82:5
+   |
+LL | fn test_call<'a, 'b, 'c>() {
+   |              -- lifetime `'a` defined here
+LL |     <Ty<'a>>::method::<Ty<'static>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:84:5
+   |
+LL | fn test_call<'a, 'b, 'c>() {
+   |                  -- lifetime `'b` defined here
+...
+LL |     <Ty<'static>>::method::<Ty<'b>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:89:5
+   |
+LL | fn test_variants<'a, 'b, 'c>() {
+   |                  -- lifetime `'a` defined here
+LL |     <Ty<'a>>::Struct {};
+   |     ^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:91:5
+   |
+LL | fn test_variants<'a, 'b, 'c>() {
+   |                      -- lifetime `'b` defined here
+...
+LL |     <Ty<'b>>::Tuple();
+   |     ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:93:5
+   |
+LL | fn test_variants<'a, 'b, 'c>() {
+   |                          -- lifetime `'c` defined here
+...
+LL |     <Ty<'c>>::Unit;
+   |     ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+   = help: replace `'c` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:98:7
+   |
+LL | fn test_method_call<'a, 'b>(x: MyTy<()>) {
+   |                     -- lifetime `'a` defined here
+LL |     x.method2::<Ty<'a>>();
+   |       ^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:100:7
+   |
+LL | fn test_method_call<'a, 'b>(x: MyTy<()>) {
+   |                         -- lifetime `'b` defined here
+...
+LL |     x.trait_method::<Ty<'b>>();
+   |       ^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:117:5
+   |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+   |                     -- lifetime `'a` defined here
+...
+LL |     MyTy::<Ty<'a>>::Struct {}; // without SelfTy
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:119:5
+   |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+   |                         -- lifetime `'b` defined here
+...
+LL |     <Ty<'b> as Project>::Enum::Struct {}; // with SelfTy
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:123:5
+   |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+   |                             -- lifetime `'c` defined here
+...
+LL |     Struct::<Ty<'c>> { x: None, }; // without SelfTy
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:125:5
+   |
+LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
+   |                                 -- lifetime `'d` defined here
+...
+LL |     <Ty<'d> as Project>::Struct { x: None, }; // with SelfTy
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+   = help: replace `'c` with `'static`
+   = help: replace `'d` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:132:9
+   |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+   |                 -- lifetime `'a` defined here
+...
+LL |         Struct::<Ty<'a>> {..} => {},
+   |         ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:134:9
+   |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+   |                     -- lifetime `'b` defined here
+...
+LL |         Tuple::<Ty<'b>> (..) => {},
+   |         ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:136:9
+   |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+   |                         -- lifetime `'c` defined here
+...
+LL |         Unit::<Ty<'c>> => {},
+   |         ^^^^^^^^^^^^^^ requires that `'c` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:141:9
+   |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+   |                             -- lifetime `'d` defined here
+...
+LL |         <Ty<'d>>::Struct {..} => {},
+   |         ^^^^^^^^^^^^^^^^^^^^^ requires that `'d` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:143:9
+   |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+   |                                 -- lifetime `'e` defined here
+...
+LL |         <Ty<'e>>::Tuple (..) => {},
+   |         ^^^^^^^^^^^^^^^^^^^^ requires that `'e` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-2.rs:145:9
+   |
+LL | fn test_pattern<'a, 'b, 'c, 'd, 'e, 'f>() {
+   |                                     -- lifetime `'f` defined here
+...
+LL |         <Ty<'f>>::Unit => {},
+   |         ^^^^^^^^^^^^^^ requires that `'f` must outlive `'static`
+
+help: the following changes may resolve your lifetime errors
+   |
+   = help: replace `'a` with `'static`
+   = help: replace `'b` with `'static`
+   = help: replace `'c` with `'static`
+   = help: replace `'d` with `'static`
+   = help: replace `'e` with `'static`
+   = help: replace `'f` with `'static`
+
+error: aborting due to 28 previous errors
+
diff --git a/src/test/ui/nll/user-annotations/normalization-default.rs b/src/test/ui/nll/user-annotations/normalization-default.rs
new file mode 100644 (file)
index 0000000..fa52e6d
--- /dev/null
@@ -0,0 +1,22 @@
+// check-fail
+
+trait Trait { type Assoc; }
+impl<'a> Trait for &'a () { type Assoc = &'a (); }
+
+struct MyTuple<T, U = <&'static () as Trait>::Assoc>(T, U);
+fn test_tuple(x: &(), y: &()) {
+    MyTuple::<_>((), x);
+    //~^ ERROR
+    let _: MyTuple::<_> = MyTuple((), y);
+    //~^ ERROR
+}
+
+struct MyStruct<T, U = <&'static () as Trait>::Assoc> { val: (T, U), }
+fn test_struct(x: &(), y: &()) {
+    MyStruct::<_> { val: ((), x) };
+    //~^ ERROR
+    let _: MyStruct::<_> = MyStruct { val: ((), y) };
+    //~^ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-default.stderr b/src/test/ui/nll/user-annotations/normalization-default.stderr
new file mode 100644 (file)
index 0000000..6c73ac6
--- /dev/null
@@ -0,0 +1,36 @@
+error: lifetime may not live long enough
+  --> $DIR/normalization-default.rs:8:22
+   |
+LL | fn test_tuple(x: &(), y: &()) {
+   |                  - let's call the lifetime of this reference `'1`
+LL |     MyTuple::<_>((), x);
+   |                      ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-default.rs:10:12
+   |
+LL | fn test_tuple(x: &(), y: &()) {
+   |                          - let's call the lifetime of this reference `'2`
+...
+LL |     let _: MyTuple::<_> = MyTuple((), y);
+   |            ^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-default.rs:16:26
+   |
+LL | fn test_struct(x: &(), y: &()) {
+   |                   - let's call the lifetime of this reference `'1`
+LL |     MyStruct::<_> { val: ((), x) };
+   |                          ^^^^^^^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-default.rs:18:12
+   |
+LL | fn test_struct(x: &(), y: &()) {
+   |                           - let's call the lifetime of this reference `'2`
+...
+LL |     let _: MyStruct::<_> = MyStruct { val: ((), y) };
+   |            ^^^^^^^^^^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/nll/user-annotations/normalization-infer.rs b/src/test/ui/nll/user-annotations/normalization-infer.rs
new file mode 100644 (file)
index 0000000..8bfc272
--- /dev/null
@@ -0,0 +1,40 @@
+// Annnotations may contain projection types with inference variables as input.
+// Make sure we don't get ambiguities when normalizing them.
+
+// check-fail
+
+// Single impl.
+fn test1<A, B, C, D>(a: A, b: B, c: C) {
+    trait Tr { type Ty; }
+    impl<T: 'static> Tr for (T,) { type Ty = T; }
+
+    let _: <(_,) as Tr>::Ty = a; //~ ERROR type `A`
+    Some::<<(_,) as Tr>::Ty>(b); //~ ERROR type `B`
+    || -> <(_,) as Tr>::Ty { c }; //~ ERROR type `C`
+    |d: <(_,) as Tr>::Ty| -> D { d }; //~ ERROR type `D`
+}
+
+
+// Two impls. The selected impl depends on the actual type.
+fn test2<A, B, C>(a: A, b: B, c: C) {
+    trait Tr { type Ty; }
+    impl<T: 'static> Tr for (u8, T) { type Ty = T; }
+    impl<T>          Tr for (i8, T) { type Ty = T; }
+    type Alias<X, Y> = (<(X, Y) as Tr>::Ty, X);
+
+    fn temp() -> String { todo!() }
+
+    // `u8` impl, requires static.
+    let _: Alias<_, _> = (a, 0u8); //~ ERROR type `A`
+    Some::<Alias<_, _>>((b, 0u8)); //~ ERROR type `B`
+    || -> Alias<_, _> { (c, 0u8) }; //~ ERROR type `C`
+
+    let _: Alias<_, _> = (&temp(), 0u8); //~ ERROR temporary value
+    Some::<Alias<_, _>>((&temp(), 0u8)); //~ ERROR temporary value
+
+    // `i8` impl, no region constraints.
+    let _: Alias<_, _> = (&temp(), 0i8);
+    Some::<Alias<_, _>>((&temp(), 0i8));
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-infer.stderr b/src/test/ui/nll/user-annotations/normalization-infer.stderr
new file mode 100644 (file)
index 0000000..12854ab
--- /dev/null
@@ -0,0 +1,101 @@
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/normalization-infer.rs:11:12
+   |
+LL |     let _: <(_,) as Tr>::Ty = a;
+   |            ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test1<A: 'static, B, C, D>(a: A, b: B, c: C) {
+   |           +++++++++
+
+error[E0310]: the parameter type `B` may not live long enough
+  --> $DIR/normalization-infer.rs:12:5
+   |
+LL |     Some::<<(_,) as Tr>::Ty>(b);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test1<A, B: 'static, C, D>(a: A, b: B, c: C) {
+   |              +++++++++
+
+error[E0310]: the parameter type `C` may not live long enough
+  --> $DIR/normalization-infer.rs:13:11
+   |
+LL |     || -> <(_,) as Tr>::Ty { c };
+   |           ^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test1<A, B, C: 'static, D>(a: A, b: B, c: C) {
+   |                 +++++++++
+
+error[E0310]: the parameter type `D` may not live long enough
+  --> $DIR/normalization-infer.rs:14:6
+   |
+LL |     |d: <(_,) as Tr>::Ty| -> D { d };
+   |      ^ ...so that the type `D` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test1<A, B, C, D: 'static>(a: A, b: B, c: C) {
+   |                    +++++++++
+
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/normalization-infer.rs:28:12
+   |
+LL |     let _: Alias<_, _> = (a, 0u8);
+   |            ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test2<A: 'static, B, C>(a: A, b: B, c: C) {
+   |           +++++++++
+
+error[E0310]: the parameter type `B` may not live long enough
+  --> $DIR/normalization-infer.rs:29:5
+   |
+LL |     Some::<Alias<_, _>>((b, 0u8));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test2<A, B: 'static, C>(a: A, b: B, c: C) {
+   |              +++++++++
+
+error[E0310]: the parameter type `C` may not live long enough
+  --> $DIR/normalization-infer.rs:30:11
+   |
+LL |     || -> Alias<_, _> { (c, 0u8) };
+   |           ^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test2<A, B, C: 'static>(a: A, b: B, c: C) {
+   |                 +++++++++
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/normalization-infer.rs:32:28
+   |
+LL |     let _: Alias<_, _> = (&temp(), 0u8);
+   |            -----------     ^^^^^^ creates a temporary value which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/normalization-infer.rs:33:27
+   |
+LL |     Some::<Alias<_, _>>((&temp(), 0u8));
+   |                         --^^^^^^------ - temporary value is freed at the end of this statement
+   |                         | |
+   |                         | creates a temporary value which is freed while still in use
+   |                         this usage requires that borrow lasts for `'static`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0310, E0716.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/nll/user-annotations/normalization-self.rs b/src/test/ui/nll/user-annotations/normalization-self.rs
new file mode 100644 (file)
index 0000000..c18760b
--- /dev/null
@@ -0,0 +1,26 @@
+// check-fail
+
+trait Trait { type Assoc; }
+impl<'a> Trait for &'a () { type Assoc = &'a (); }
+
+struct MyTuple<T>(T);
+impl MyTuple<<&'static () as Trait>::Assoc> {
+    fn test(x: &(), y: &()) {
+        Self(x);
+        //~^ ERROR
+        let _: Self = MyTuple(y);
+        //~^ ERROR
+    }
+}
+
+struct MyStruct<T> { val: T, }
+impl MyStruct<<&'static () as Trait>::Assoc> {
+    fn test(x: &(), y: &()) {
+        Self { val: x };
+        //~^ ERROR
+        let _: Self = MyStruct { val: y };
+        //~^ ERROR
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/normalization-self.stderr b/src/test/ui/nll/user-annotations/normalization-self.stderr
new file mode 100644 (file)
index 0000000..e231ed0
--- /dev/null
@@ -0,0 +1,36 @@
+error: lifetime may not live long enough
+  --> $DIR/normalization-self.rs:9:14
+   |
+LL |     fn test(x: &(), y: &()) {
+   |                - let's call the lifetime of this reference `'1`
+LL |         Self(x);
+   |              ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-self.rs:11:16
+   |
+LL |     fn test(x: &(), y: &()) {
+   |                        - let's call the lifetime of this reference `'2`
+...
+LL |         let _: Self = MyTuple(y);
+   |                ^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-self.rs:19:21
+   |
+LL |     fn test(x: &(), y: &()) {
+   |                - let's call the lifetime of this reference `'1`
+LL |         Self { val: x };
+   |                     ^ this usage requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/normalization-self.rs:21:16
+   |
+LL |     fn test(x: &(), y: &()) {
+   |                        - let's call the lifetime of this reference `'2`
+...
+LL |         let _: Self = MyStruct { val: y };
+   |                ^^^^ type annotation requires that `'2` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
index 870e3d8110cd5e34b487a02157a0da808d240da1..c2e892f573c2d6fa6ebc7372111dffed096bc19f 100644 (file)
@@ -3,8 +3,15 @@
 
 trait Foo { type Out; }
 impl Foo for () { type Out = &'static u32; }
+impl<'a> Foo for &'a () { type Out = &'a u32; }
 
 fn main() {
     let a = 22;
-    let b: <() as Foo>::Out = &a; //~ ERROR
+    let _: <() as Foo>::Out = &a; //~ ERROR
+
+    let a = 22;
+    let _: <&'static () as Foo>::Out = &a; //~ ERROR
+
+    let a = 22;
+    let _: <&'_ () as Foo>::Out = &a;
 }
index 4c7893789a53516cf57d10500cff3db0bd89cf7c..975cb4b66d91d0ef91004d6524d5f21786f43878 100644 (file)
@@ -1,13 +1,25 @@
 error[E0597]: `a` does not live long enough
-  --> $DIR/normalization.rs:9:31
+  --> $DIR/normalization.rs:10:31
    |
-LL |     let b: <() as Foo>::Out = &a;
+LL |     let _: <() as Foo>::Out = &a;
    |            ----------------   ^^ borrowed value does not live long enough
    |            |
    |            type annotation requires that `a` is borrowed for `'static`
+...
 LL | }
    | - `a` dropped here while still borrowed
 
-error: aborting due to previous error
+error[E0597]: `a` does not live long enough
+  --> $DIR/normalization.rs:13:40
+   |
+LL |     let _: <&'static () as Foo>::Out = &a;
+   |            -------------------------   ^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `a` is borrowed for `'static`
+...
+LL | }
+   | - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0597`.
index 424762551887138ec0e8dd4a8af250b5c7bcc3ed..4a2ea5e44c71adec08866bd3e5a85471470cf1ac 100644 (file)
@@ -25,7 +25,7 @@ fn bar(
 
 fn main() {
   foo(1, 2, 3);
-  //~^ ERROR this function takes 4 arguments but 3
+  //~^ ERROR function takes 4 arguments but 3
   bar(1, 2, 3);
-  //~^ ERROR this function takes 6 arguments but 3
+  //~^ ERROR function takes 6 arguments but 3
 }
diff --git a/src/test/ui/object-safety/issue-106247.rs b/src/test/ui/object-safety/issue-106247.rs
new file mode 100644 (file)
index 0000000..64bf59e
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+#![deny(where_clauses_object_safety)]
+
+pub trait Trait {
+    fn method(&self) where Self: Sync;
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/diff-markers/enum-2.rs b/src/test/ui/parser/diff-markers/enum-2.rs
new file mode 100644 (file)
index 0000000..76ea980
--- /dev/null
@@ -0,0 +1,11 @@
+enum E {
+    Foo {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+        x: u8,
+|||||||
+        z: (),
+=======
+        y: i8,
+>>>>>>> branch
+    }
+}
diff --git a/src/test/ui/parser/diff-markers/enum-2.stderr b/src/test/ui/parser/diff-markers/enum-2.stderr
new file mode 100644 (file)
index 0000000..63da5c2
--- /dev/null
@@ -0,0 +1,21 @@
+error: encountered diff marker
+  --> $DIR/enum-2.rs:3:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |         x: u8,
+LL | |||||||
+   | -------
+LL |         z: (),
+LL | =======
+   | -------
+LL |         y: i8,
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/enum.rs b/src/test/ui/parser/diff-markers/enum.rs
new file mode 100644 (file)
index 0000000..45df6e3
--- /dev/null
@@ -0,0 +1,7 @@
+enum E {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+    Foo(u8),
+=======
+    Bar(i8),
+>>>>>>> branch
+}
diff --git a/src/test/ui/parser/diff-markers/enum.stderr b/src/test/ui/parser/diff-markers/enum.stderr
new file mode 100644 (file)
index 0000000..abbf3fb
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/enum.rs:2:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |     Foo(u8),
+LL | =======
+   | -------
+LL |     Bar(i8),
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/fn-arg.rs b/src/test/ui/parser/diff-markers/fn-arg.rs
new file mode 100644 (file)
index 0000000..86c3556
--- /dev/null
@@ -0,0 +1,16 @@
+trait T {
+    fn foo(
+<<<<<<< HEAD //~ ERROR encountered diff marker
+        x: u8,
+=======
+        x: i8,
+>>>>>>> branch
+    ) {}
+}
+
+struct S;
+impl T for S {}
+
+fn main() {
+    S::foo(42);
+}
diff --git a/src/test/ui/parser/diff-markers/fn-arg.stderr b/src/test/ui/parser/diff-markers/fn-arg.stderr
new file mode 100644 (file)
index 0000000..933a206
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/fn-arg.rs:3:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |         x: u8,
+LL | =======
+   | -------
+LL |         x: i8,
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/item-with-attr.rs b/src/test/ui/parser/diff-markers/item-with-attr.rs
new file mode 100644 (file)
index 0000000..985907c
--- /dev/null
@@ -0,0 +1,10 @@
+#[attribute]
+<<<<<<< HEAD //~ ERROR encountered diff marker
+fn foo() {}
+=======
+fn bar() {}
+>>>>>>> branch
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/parser/diff-markers/item-with-attr.stderr b/src/test/ui/parser/diff-markers/item-with-attr.stderr
new file mode 100644 (file)
index 0000000..850e236
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/item-with-attr.rs:2:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL | fn foo() {}
+LL | =======
+   | -------
+LL | fn bar() {}
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/item.rs b/src/test/ui/parser/diff-markers/item.rs
new file mode 100644 (file)
index 0000000..4ed36b7
--- /dev/null
@@ -0,0 +1,9 @@
+<<<<<<< HEAD //~ ERROR encountered diff marker
+fn foo() {}
+=======
+fn bar() {}
+>>>>>>> branch
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/parser/diff-markers/item.stderr b/src/test/ui/parser/diff-markers/item.stderr
new file mode 100644 (file)
index 0000000..9ab3631
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/item.rs:1:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL | fn foo() {}
+LL | =======
+   | -------
+LL | fn bar() {}
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/statement.rs b/src/test/ui/parser/diff-markers/statement.rs
new file mode 100644 (file)
index 0000000..e55d16d
--- /dev/null
@@ -0,0 +1,15 @@
+trait T {
+    fn foo() {}
+    fn bar() {}
+}
+
+struct S;
+impl T for S {}
+
+fn main() {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+    S::foo();
+=======
+    S::bar();
+>>>>>>> branch
+}
diff --git a/src/test/ui/parser/diff-markers/statement.stderr b/src/test/ui/parser/diff-markers/statement.stderr
new file mode 100644 (file)
index 0000000..7ca2495
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/statement.rs:10:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |     S::foo();
+LL | =======
+   | -------
+LL |     S::bar();
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/struct-expr.rs b/src/test/ui/parser/diff-markers/struct-expr.rs
new file mode 100644 (file)
index 0000000..99d2fd6
--- /dev/null
@@ -0,0 +1,12 @@
+struct S {
+    x: u8,
+}
+fn main() {
+    let _ = S {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+        x: 42,
+=======
+        x: 0,
+>>>>>>> branch
+    }
+}
diff --git a/src/test/ui/parser/diff-markers/struct-expr.stderr b/src/test/ui/parser/diff-markers/struct-expr.stderr
new file mode 100644 (file)
index 0000000..d70476a
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/struct-expr.rs:6:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |         x: 42,
+LL | =======
+   | -------
+LL |         x: 0,
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/struct.rs b/src/test/ui/parser/diff-markers/struct.rs
new file mode 100644 (file)
index 0000000..d26464d
--- /dev/null
@@ -0,0 +1,7 @@
+struct S {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+    x: u8,
+=======
+    x: i8,
+>>>>>>> branch
+}
diff --git a/src/test/ui/parser/diff-markers/struct.stderr b/src/test/ui/parser/diff-markers/struct.stderr
new file mode 100644 (file)
index 0000000..cc0b3da
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/struct.rs:2:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |     x: u8,
+LL | =======
+   | -------
+LL |     x: i8,
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/trait-item.rs b/src/test/ui/parser/diff-markers/trait-item.rs
new file mode 100644 (file)
index 0000000..3227c82
--- /dev/null
@@ -0,0 +1,14 @@
+trait T {
+<<<<<<< HEAD //~ ERROR encountered diff marker
+    fn foo() {}
+=======
+    fn bar() {}
+>>>>>>> branch
+}
+
+struct S;
+impl T for S {}
+
+fn main() {
+    S::foo();
+}
diff --git a/src/test/ui/parser/diff-markers/trait-item.stderr b/src/test/ui/parser/diff-markers/trait-item.stderr
new file mode 100644 (file)
index 0000000..cdc19f8
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/trait-item.rs:2:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |     fn foo() {}
+LL | =======
+   | -------
+LL |     fn bar() {}
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/tuple-struct.rs b/src/test/ui/parser/diff-markers/tuple-struct.rs
new file mode 100644 (file)
index 0000000..7eec35c
--- /dev/null
@@ -0,0 +1,7 @@
+struct S(
+<<<<<<< HEAD //~ ERROR encountered diff marker
+    u8,
+=======
+    i8,
+>>>>>>> branch
+);
diff --git a/src/test/ui/parser/diff-markers/tuple-struct.stderr b/src/test/ui/parser/diff-markers/tuple-struct.stderr
new file mode 100644 (file)
index 0000000..d673db8
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/tuple-struct.rs:2:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |     u8,
+LL | =======
+   | -------
+LL |     i8,
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/diff-markers/use-statement.rs b/src/test/ui/parser/diff-markers/use-statement.rs
new file mode 100644 (file)
index 0000000..6306243
--- /dev/null
@@ -0,0 +1,9 @@
+use foo::{
+<<<<<<< HEAD //~ ERROR encountered diff marker
+    bar,
+=======
+    baz,
+>>>>>>> branch
+};
+
+fn main() {}
diff --git a/src/test/ui/parser/diff-markers/use-statement.stderr b/src/test/ui/parser/diff-markers/use-statement.stderr
new file mode 100644 (file)
index 0000000..12e6f57
--- /dev/null
@@ -0,0 +1,18 @@
+error: encountered diff marker
+  --> $DIR/use-statement.rs:2:1
+   |
+LL | <<<<<<< HEAD
+   | ^^^^^^^ after this is the code before the merge
+LL |     bar,
+LL | =======
+   | -------
+LL |     baz,
+LL | >>>>>>> branch
+   | ^^^^^^^ above this are the incoming code changes
+   |
+   = help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
+   = help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
+   = note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
+
+error: aborting due to previous error
+
index 7cae85fc9fe6d433731e5f6f702a1fbe06ed15da..49d6aa5eff8ceee845bf6295d5604255be866ce7 100644 (file)
@@ -3,6 +3,8 @@ error: integer literal is too large
    |
 LL |     9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/intersection-patterns-1.fixed b/src/test/ui/parser/intersection-patterns-1.fixed
new file mode 100644 (file)
index 0000000..4477309
--- /dev/null
@@ -0,0 +1,35 @@
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+// run-rustfix
+
+#![allow(unused_variables)]
+
+fn main() {
+    let s: Option<u8> = None;
+
+    match s {
+        y @ Some(x) => {}
+        //~^ ERROR pattern on wrong side of `@`
+        //~| pattern on the left, should be on the right
+        //~| binding on the right, should be on the left
+        //~| HELP switch the order
+        //~| SUGGESTION y @ Some(x)
+        _ => {}
+    }
+
+    match 2 {
+        e @ 1..=5 => {}
+        //~^ ERROR pattern on wrong side of `@`
+        //~| pattern on the left, should be on the right
+        //~| binding on the right, should be on the left
+        //~| HELP switch the order
+        //~| SUGGESTION e @ 1..=5
+        _ => {}
+    }
+}
diff --git a/src/test/ui/parser/intersection-patterns-1.rs b/src/test/ui/parser/intersection-patterns-1.rs
new file mode 100644 (file)
index 0000000..1036b9d
--- /dev/null
@@ -0,0 +1,35 @@
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+// run-rustfix
+
+#![allow(unused_variables)]
+
+fn main() {
+    let s: Option<u8> = None;
+
+    match s {
+        Some(x) @ y => {}
+        //~^ ERROR pattern on wrong side of `@`
+        //~| pattern on the left, should be on the right
+        //~| binding on the right, should be on the left
+        //~| HELP switch the order
+        //~| SUGGESTION y @ Some(x)
+        _ => {}
+    }
+
+    match 2 {
+        1 ..= 5 @ e => {}
+        //~^ ERROR pattern on wrong side of `@`
+        //~| pattern on the left, should be on the right
+        //~| binding on the right, should be on the left
+        //~| HELP switch the order
+        //~| SUGGESTION e @ 1..=5
+        _ => {}
+    }
+}
diff --git a/src/test/ui/parser/intersection-patterns-1.stderr b/src/test/ui/parser/intersection-patterns-1.stderr
new file mode 100644 (file)
index 0000000..dc96865
--- /dev/null
@@ -0,0 +1,22 @@
+error: pattern on wrong side of `@`
+  --> $DIR/intersection-patterns-1.rs:17:9
+   |
+LL |         Some(x) @ y => {}
+   |         -------^^^-
+   |         |         |
+   |         |         binding on the right, should be on the left
+   |         pattern on the left, should be on the right
+   |         help: switch the order: `y @ Some(x)`
+
+error: pattern on wrong side of `@`
+  --> $DIR/intersection-patterns-1.rs:27:9
+   |
+LL |         1 ..= 5 @ e => {}
+   |         -------^^^-
+   |         |         |
+   |         |         binding on the right, should be on the left
+   |         pattern on the left, should be on the right
+   |         help: switch the order: `e @ 1..=5`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/intersection-patterns-2.rs b/src/test/ui/parser/intersection-patterns-2.rs
new file mode 100644 (file)
index 0000000..408415e
--- /dev/null
@@ -0,0 +1,20 @@
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+fn main() {
+    let s: Option<u8> = None;
+
+    match s {
+        Some(x) @ Some(y) => {}
+        //~^ ERROR left-hand side of `@` must be a binding
+        //~| interpreted as a pattern, not a binding
+        //~| also a pattern
+        //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+        _ => {}
+    }
+}
diff --git a/src/test/ui/parser/intersection-patterns-2.stderr b/src/test/ui/parser/intersection-patterns-2.stderr
new file mode 100644 (file)
index 0000000..f7e7881
--- /dev/null
@@ -0,0 +1,13 @@
+error: left-hand side of `@` must be a binding
+  --> $DIR/intersection-patterns-2.rs:13:9
+   |
+LL |         Some(x) @ Some(y) => {}
+   |         -------^^^-------
+   |         |         |
+   |         |         also a pattern
+   |         interpreted as a pattern, not a binding
+   |
+   = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/intersection-patterns.rs b/src/test/ui/parser/intersection-patterns.rs
deleted file mode 100644 (file)
index a6d27aa..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// This tests the parser recovery in `recover_intersection_pat`
-// and serves as a regression test for the diagnostics issue #65400.
-//
-// The general idea is that for `$pat_lhs @ $pat_rhs` where
-// `$pat_lhs` is not generated by `ref? mut? $ident` we want
-// to suggest either switching the order or note that intersection
-// patterns are not allowed.
-
-fn main() {
-    let s: Option<u8> = None;
-
-    match s {
-        Some(x) @ y => {}
-        //~^ ERROR pattern on wrong side of `@`
-        //~| pattern on the left, should be on the right
-        //~| binding on the right, should be on the left
-        //~| HELP switch the order
-        //~| SUGGESTION y @ Some(x)
-        _ => {}
-    }
-
-    match s {
-        Some(x) @ Some(y) => {}
-        //~^ ERROR left-hand side of `@` must be a binding
-        //~| interpreted as a pattern, not a binding
-        //~| also a pattern
-        //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x`
-        _ => {}
-    }
-
-    match 2 {
-        1 ..= 5 @ e => {}
-        //~^ ERROR pattern on wrong side of `@`
-        //~| pattern on the left, should be on the right
-        //~| binding on the right, should be on the left
-        //~| HELP switch the order
-        //~| SUGGESTION e @ 1..=5
-        _ => {}
-    }
-}
diff --git a/src/test/ui/parser/intersection-patterns.stderr b/src/test/ui/parser/intersection-patterns.stderr
deleted file mode 100644 (file)
index 9dc4c46..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-error: pattern on wrong side of `@`
-  --> $DIR/intersection-patterns.rs:13:9
-   |
-LL |         Some(x) @ y => {}
-   |         -------^^^-
-   |         |         |
-   |         |         binding on the right, should be on the left
-   |         pattern on the left, should be on the right
-   |         help: switch the order: `y @ Some(x)`
-
-error: left-hand side of `@` must be a binding
-  --> $DIR/intersection-patterns.rs:23:9
-   |
-LL |         Some(x) @ Some(y) => {}
-   |         -------^^^-------
-   |         |         |
-   |         |         also a pattern
-   |         interpreted as a pattern, not a binding
-   |
-   = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
-
-error: pattern on wrong side of `@`
-  --> $DIR/intersection-patterns.rs:32:9
-   |
-LL |         1 ..= 5 @ e => {}
-   |         -------^^^-
-   |         |         |
-   |         |         binding on the right, should be on the left
-   |         pattern on the left, should be on the right
-   |         help: switch the order: `e @ 1..=5`
-
-error: aborting due to 3 previous errors
-
index de579c3c134e511d8a7e5e1bc6b8409591303d7f..6e68c75850afe576d6b25e4bf5fe8213bf720c2f 100644 (file)
@@ -3,6 +3,8 @@ error: integer literal is too large
    |
 LL |     let __isize = 340282366920938463463374607431768211456; // 2^128
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
 
 error: aborting due to previous error
 
index 7df212dedfede1fb6dd496297eb0713a47ebfac4..5d0e76d5d9445ce007477a430484ccb21068c348 100644 (file)
@@ -3,6 +3,8 @@ error: integer literal is too large
    |
 LL |     let __isize = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ff;
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `0xffffffffffffffffffffffffffffffff`
 
 error: aborting due to previous error
 
index fa037e5937dcaccfed179d0277b30eb85efe5c21..e9e85339affa9e1da8bd6aee63e272f04b1a8d08 100644 (file)
@@ -4,21 +4,13 @@ fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
 //~^ ERROR expected identifier, found keyword `fn`
 //~| ERROR expected identifier, found keyword `fn`
 //~| ERROR expected identifier, found keyword `fn`
-//~| ERROR cannot find trait `r#fn` in this scope
-//~| ERROR cannot find trait `r#fn` in this scope
-//~| ERROR cannot find trait `r#fn` in this scope
-//~| HELP  a trait with a similar name exists
-//~| HELP  a trait with a similar name exists
-//~| HELP  a trait with a similar name exists
-//~| HELP  escape `fn` to use it as an identifier
-//~| HELP  escape `fn` to use it as an identifier
-//~| HELP  escape `fn` to use it as an identifier
+//~| HELP use `Fn` to refer to the trait
+//~| HELP use `Fn` to refer to the trait
+//~| HELP use `Fn` to refer to the trait
 where
 G: fn(),
     //~^ ERROR expected identifier, found keyword `fn`
-    //~| ERROR cannot find trait `r#fn` in this scope
-    //~| HELP  a trait with a similar name exists
-    //~| HELP  escape `fn` to use it as an identifier
+    //~| HELP use `Fn` to refer to the trait
 {}
 
 fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
index 79643660e8b0078c73e70de919e0fd285dc0f415..2d3aad4d6baf46f5a7733566b7436de8663b44f6 100644 (file)
@@ -2,48 +2,48 @@ error: expected identifier, found keyword `fn`
   --> $DIR/kw-in-trait-bounds.rs:3:10
    |
 LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
-   |          ^^ expected identifier, found keyword
+   |          ^^
    |
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
    |
-LL | fn _f<F: r#fn(), G>(_: impl fn(), _: &dyn fn())
-   |          ++
+LL | fn _f<F: Fn(), G>(_: impl fn(), _: &dyn fn())
+   |          ~~
 
 error: expected identifier, found keyword `fn`
   --> $DIR/kw-in-trait-bounds.rs:3:27
    |
 LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
-   |                           ^^ expected identifier, found keyword
+   |                           ^^
    |
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
    |
-LL | fn _f<F: fn(), G>(_: impl r#fn(), _: &dyn fn())
-   |                           ++
+LL | fn _f<F: fn(), G>(_: impl Fn(), _: &dyn fn())
+   |                           ~~
 
 error: expected identifier, found keyword `fn`
   --> $DIR/kw-in-trait-bounds.rs:3:41
    |
 LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
-   |                                         ^^ expected identifier, found keyword
+   |                                         ^^
    |
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
    |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn r#fn())
-   |                                         ++
+LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn Fn())
+   |                                         ~~
 
 error: expected identifier, found keyword `fn`
-  --> $DIR/kw-in-trait-bounds.rs:17:4
+  --> $DIR/kw-in-trait-bounds.rs:11:4
    |
 LL | G: fn(),
-   |    ^^ expected identifier, found keyword
+   |    ^^
    |
-help: escape `fn` to use it as an identifier
+help: use `Fn` to refer to the trait
    |
-LL | G: r#fn(),
-   |    ++
+LL | G: Fn(),
+   |    ~~
 
 error: expected identifier, found keyword `struct`
-  --> $DIR/kw-in-trait-bounds.rs:24:10
+  --> $DIR/kw-in-trait-bounds.rs:16:10
    |
 LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
    |          ^^^^^^ expected identifier, found keyword
@@ -54,7 +54,7 @@ LL | fn _g<A: r#struct, B>(_: impl struct, _: &dyn struct)
    |          ++
 
 error: expected identifier, found keyword `struct`
-  --> $DIR/kw-in-trait-bounds.rs:24:29
+  --> $DIR/kw-in-trait-bounds.rs:16:29
    |
 LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
    |                             ^^^^^^ expected identifier, found keyword
@@ -65,7 +65,7 @@ LL | fn _g<A: struct, B>(_: impl r#struct, _: &dyn struct)
    |                             ++
 
 error: expected identifier, found keyword `struct`
-  --> $DIR/kw-in-trait-bounds.rs:24:45
+  --> $DIR/kw-in-trait-bounds.rs:16:45
    |
 LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
    |                                             ^^^^^^ expected identifier, found keyword
@@ -76,7 +76,7 @@ LL | fn _g<A: struct, B>(_: impl struct, _: &dyn r#struct)
    |                                             ++
 
 error: expected identifier, found keyword `struct`
-  --> $DIR/kw-in-trait-bounds.rs:38:8
+  --> $DIR/kw-in-trait-bounds.rs:30:8
    |
 LL |     B: struct,
    |        ^^^^^^ expected identifier, found keyword
@@ -86,44 +86,8 @@ help: escape `struct` to use it as an identifier
 LL |     B: r#struct,
    |        ++
 
-error[E0405]: cannot find trait `r#fn` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:3:10
-   |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
-   |          ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-   = note: similarly named trait `Fn` defined here
-
-error[E0405]: cannot find trait `r#fn` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:17:4
-   |
-LL | G: fn(),
-   |    ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-   = note: similarly named trait `Fn` defined here
-
-error[E0405]: cannot find trait `r#fn` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:3:27
-   |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
-   |                           ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-   = note: similarly named trait `Fn` defined here
-
-error[E0405]: cannot find trait `r#fn` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:3:41
-   |
-LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
-   |                                         ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-   = note: similarly named trait `Fn` defined here
-
 error[E0405]: cannot find trait `r#struct` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:24:10
+  --> $DIR/kw-in-trait-bounds.rs:16:10
    |
 LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
    |          ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
@@ -132,7 +96,7 @@ LL | trait Struct {}
    | ------------ similarly named trait `Struct` defined here
 
 error[E0405]: cannot find trait `r#struct` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:38:8
+  --> $DIR/kw-in-trait-bounds.rs:30:8
    |
 LL |     B: struct,
    |        ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
@@ -141,7 +105,7 @@ LL | trait Struct {}
    | ------------ similarly named trait `Struct` defined here
 
 error[E0405]: cannot find trait `r#struct` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:24:29
+  --> $DIR/kw-in-trait-bounds.rs:16:29
    |
 LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
    |                             ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
@@ -150,7 +114,7 @@ LL | trait Struct {}
    | ------------ similarly named trait `Struct` defined here
 
 error[E0405]: cannot find trait `r#struct` in this scope
-  --> $DIR/kw-in-trait-bounds.rs:24:45
+  --> $DIR/kw-in-trait-bounds.rs:16:45
    |
 LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
    |                                             ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
@@ -158,6 +122,6 @@ LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
 LL | trait Struct {}
    | ------------ similarly named trait `Struct` defined here
 
-error: aborting due to 16 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0405`.
diff --git a/src/test/ui/parser/nested-bad-turbofish.rs b/src/test/ui/parser/nested-bad-turbofish.rs
new file mode 100644 (file)
index 0000000..02099fd
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    foo<<S as T>::V>(); //~ ERROR
+}
diff --git a/src/test/ui/parser/nested-bad-turbofish.stderr b/src/test/ui/parser/nested-bad-turbofish.stderr
new file mode 100644 (file)
index 0000000..d82fa80
--- /dev/null
@@ -0,0 +1,11 @@
+error: comparison operators cannot be chained
+  --> $DIR/nested-bad-turbofish.rs:2:16
+   |
+LL |     foo<<S as T>::V>();
+   |                ^   ^
+   |
+   = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   = help: or use `(...)` if you meant to specify fn arguments
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/recover-fn-trait-from-fn-kw.rs b/src/test/ui/parser/recover-fn-trait-from-fn-kw.rs
new file mode 100644 (file)
index 0000000..b6611e6
--- /dev/null
@@ -0,0 +1,12 @@
+fn foo(_: impl fn() -> i32) {}
+//~^ ERROR expected identifier, found keyword `fn`
+
+fn foo2<T: fn(i32)>(_: T) {}
+//~^ ERROR expected identifier, found keyword `fn`
+
+fn main() {
+    foo(|| ());
+    //~^ mismatched types
+    foo2(|_: ()| {});
+    //~^ type mismatch in closure arguments
+}
diff --git a/src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr b/src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr
new file mode 100644 (file)
index 0000000..3681a79
--- /dev/null
@@ -0,0 +1,48 @@
+error: expected identifier, found keyword `fn`
+  --> $DIR/recover-fn-trait-from-fn-kw.rs:1:16
+   |
+LL | fn foo(_: impl fn() -> i32) {}
+   |                ^^
+   |
+help: use `Fn` to refer to the trait
+   |
+LL | fn foo(_: impl Fn() -> i32) {}
+   |                ~~
+
+error: expected identifier, found keyword `fn`
+  --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12
+   |
+LL | fn foo2<T: fn(i32)>(_: T) {}
+   |            ^^
+   |
+help: use `Fn` to refer to the trait
+   |
+LL | fn foo2<T: Fn(i32)>(_: T) {}
+   |            ~~
+
+error[E0308]: mismatched types
+  --> $DIR/recover-fn-trait-from-fn-kw.rs:8:12
+   |
+LL |     foo(|| ());
+   |            ^^ expected `i32`, found `()`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/recover-fn-trait-from-fn-kw.rs:10:5
+   |
+LL |     foo2(|_: ()| {});
+   |     ^^^^ ------- found signature defined here
+   |     |
+   |     expected due to this
+   |
+   = note: expected closure signature `fn(i32) -> _`
+              found closure signature `fn(()) -> _`
+note: required by a bound in `foo2`
+  --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12
+   |
+LL | fn foo2<T: fn(i32)>(_: T) {}
+   |            ^^^^^^^ required by this bound in `foo2`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
index 70beb5d423223888072bf6072c552320a1d5c96b..54118dc367770cc90c2a71bbcbd40c9499045594 100644 (file)
@@ -1,20 +1,24 @@
 error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
   --> $DIR/nested-binding-modes-mut.rs:4:5
    |
-LL |     let mut is_mut @ not_mut = 42;
-   |                      ------- help: consider changing this to be mutable: `mut not_mut`
-LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut is_mut @ mut not_mut = 42;
+   |                      +++
 
 error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
   --> $DIR/nested-binding-modes-mut.rs:9:5
    |
-LL |     let not_mut @ mut is_mut = 42;
-   |         ------- help: consider changing this to be mutable: `mut not_mut`
-LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut not_mut @ mut is_mut = 42;
+   |         +++
 
 error: aborting due to 2 previous errors
 
index bb7b818368b78dca3969c32b35f92d5c45371b04..1b93267b397714cf694a084d0b7a3da0100c90dd 100644 (file)
@@ -104,20 +104,24 @@ LL |     *_x0 = U;
 error[E0594]: cannot assign to `*_x0`, which is behind a `&` reference
   --> $DIR/borrowck-move-ref-pattern.rs:26:5
    |
-LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
-   |          ------- help: consider changing this to be a mutable reference: `ref mut _x0`
-...
 LL |     *_x0 = U;
    |     ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let (ref mut _x0, _x1, ref _x2, ..) = tup;
+   |          ~~~~~~~~~~~
 
 error[E0594]: cannot assign to `*_x2`, which is behind a `&` reference
   --> $DIR/borrowck-move-ref-pattern.rs:27:5
    |
-LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
-   |                        ------- help: consider changing this to be a mutable reference: `ref mut _x2`
-...
 LL |     *_x2 = U;
    |     ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let (ref _x0, _x1, ref mut _x2, ..) = tup;
+   |                        ~~~~~~~~~~~
 
 error[E0382]: use of moved value: `tup.1`
   --> $DIR/borrowck-move-ref-pattern.rs:28:10
diff --git a/src/test/ui/privacy/private-field-ty-err.rs b/src/test/ui/privacy/private-field-ty-err.rs
new file mode 100644 (file)
index 0000000..10db606
--- /dev/null
@@ -0,0 +1,20 @@
+fn main() {
+    let x = foo::Foo::default();
+    if x.len {
+        //~^ ERROR field `len` of struct `Foo` is private
+        println!("foo");
+    }
+}
+
+mod foo {
+    #[derive(Default)]
+    pub struct Foo {
+        len: String,
+    }
+
+    impl Foo {
+        pub fn len(&self) -> usize {
+            42
+        }
+    }
+}
diff --git a/src/test/ui/privacy/private-field-ty-err.stderr b/src/test/ui/privacy/private-field-ty-err.stderr
new file mode 100644 (file)
index 0000000..e583a25
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0616]: field `len` of struct `Foo` is private
+  --> $DIR/private-field-ty-err.rs:3:10
+   |
+LL |     if x.len {
+   |          ^^^ private field
+   |
+help: a method `len` also exists, call it with parentheses
+   |
+LL |     if x.len() {
+   |             ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0616`.
index 6d4d24922253d112720cc54e916cb58f75fc5760..da2683121735f1176f97775866fbd4e6973ecbcb 100644 (file)
@@ -84,42 +84,47 @@ fn expect_aborted(status: ExitStatus) {
 
     #[cfg(target_os = "android")]
     {
-        // Android signals an abort() call with SIGSEGV at address 0xdeadbaad
-        // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
-        assert!(signal == libc::SIGSEGV);
-
-        // Additional checks performed:
-        // 1. Find last tombstone (similar to coredump but in text format) from the
-        //    same executable (path) as we are (must be because of usage of fork):
-        //    This ensures that we look into the correct tombstone.
-        // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
-        // 3. libc::abort call is in one of top two functions on callstack.
-        // The last two steps distinguish between a normal SIGSEGV and one caused
-        // by libc::abort.
-
-        let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
-        let exe_string = format!(">>> {this_exe} <<<");
-        let tombstone = (0..100)
-            .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
-            .filter(|f| std::path::Path::new(&f).exists())
-            .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
-            .filter(|f| f.contains(&exe_string))
-            .last()
-            .expect("no tombstone found");
-
-        println!("Content of tombstone:\n{tombstone}");
-
-        assert!(
-            tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad")
-        );
-        let abort_on_top = tombstone
-            .lines()
-            .skip_while(|l| !l.contains("backtrace:"))
-            .skip(1)
-            .take_while(|l| l.starts_with("    #"))
-            .take(2)
-            .any(|f| f.contains("/system/lib/libc.so (abort"));
-        assert!(abort_on_top);
+        assert!(signal == libc::SIGABRT || signal == libc::SIGSEGV);
+
+        if signal == libc::SIGSEGV {
+            // Pre-KitKat versions of Android signal an abort() with SIGSEGV at address 0xdeadbaad
+            // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
+            //
+            // This behavior was changed in KitKat to send a standard SIGABRT signal.
+            // See: https://r.android.com/60341
+            //
+            // Additional checks performed:
+            // 1. Find last tombstone (similar to coredump but in text format) from the
+            //    same executable (path) as we are (must be because of usage of fork):
+            //    This ensures that we look into the correct tombstone.
+            // 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
+            // 3. libc::abort call is in one of top two functions on callstack.
+            // The last two steps distinguish between a normal SIGSEGV and one caused
+            // by libc::abort.
+
+            let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
+            let exe_string = format!(">>> {this_exe} <<<");
+            let tombstone = (0..100)
+                .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
+                .filter(|f| std::path::Path::new(&f).exists())
+                .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
+                .filter(|f| f.contains(&exe_string))
+                .last()
+                .expect("no tombstone found");
+
+            println!("Content of tombstone:\n{tombstone}");
+
+            assert!(tombstone
+                .contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"));
+            let abort_on_top = tombstone
+                .lines()
+                .skip_while(|l| !l.contains("backtrace:"))
+                .skip(1)
+                .take_while(|l| l.starts_with("    #"))
+                .take(2)
+                .any(|f| f.contains("/system/lib/libc.so (abort"));
+            assert!(abort_on_top);
+        }
     }
 }
 
index 87e33e1ccff29a2d050bfacd03abda5b37523bfb..2a26252036181ceb696733b2902ac6b0f628ab49 100644 (file)
@@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
    |               lifetime `'a` defined here
 ...
 LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
index c79ed50c6a4a6bc64513b19eab863a4e88e7c142..cdf70d2a5be974245001d8deb05d352a991fd56e 100644 (file)
@@ -6,7 +6,7 @@ LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
    |          |
    |          lifetime `'a` defined here
 LL |     let z: Option<&'b &'a usize> = None;
-   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+   |            ^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -19,7 +19,7 @@ LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
    |          lifetime `'a` defined here
 LL |     let y: Paramd<'a> = Paramd { x: a };
 LL |     let z: Option<&'b Paramd<'a>> = None;
-   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -31,7 +31,7 @@ LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
    |          |
    |          lifetime `'a` defined here
 LL |     let z: Option<&'a &'b usize> = None;
-   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |            ^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
index 66f592c34dd070ada24e0e826d4dd25c017eac99..3fd39810d445397b1cd151b0160d1e74db31bd10 100644 (file)
@@ -1,12 +1,8 @@
 error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
-  --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1
+  --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49
    |
-LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
-LL | |
-LL | |
-LL | | {
-LL | | }
-   | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
+LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
@@ -14,10 +10,14 @@ LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T
    |                    ++++++++++++++++++++++++
 
 error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
-  --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49
+  --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1
    |
-LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
+LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
+LL | |
+LL | |
+LL | | {
+LL | | }
+   | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
index 187e9056e115d3ca2f612718cef5e08d72b5d3da..6a7c908fa40092873b4d5518f83471530903448d 100644 (file)
@@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
    |               lifetime `'a` defined here
 ...
 LL |     let _: &'a WithHrAssoc<TheType<'b>> = loop { };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
@@ -20,7 +20,7 @@ LL | fn with_assoc_sub<'a,'b>() {
    |                   lifetime `'a` defined here
 ...
 LL |     let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
index 4178e951c86ed23f302f97ae07900ced4cdd5477..eba2a0d585346a0fb49d36811c3cc8ff731af218 100644 (file)
@@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
    |               lifetime `'a` defined here
 ...
 LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
index 073a31900227e43e357b339d947df136eba08b9a..d20a2f06adfeccf818141a5dca2c4cf98ae799c4 100644 (file)
@@ -7,7 +7,7 @@ LL | fn with_assoc<'a,'b>() {
    |               lifetime `'a` defined here
 ...
 LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
@@ -20,7 +20,7 @@ LL | fn without_assoc<'a,'b>() {
    |                  lifetime `'a` defined here
 ...
 LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/repr/transparent-enum-too-many-variants.rs b/src/test/ui/repr/transparent-enum-too-many-variants.rs
new file mode 100644 (file)
index 0000000..0dd4b4e
--- /dev/null
@@ -0,0 +1,10 @@
+use std::mem::size_of;
+
+#[repr(transparent)]
+enum Foo { //~ ERROR E0731
+    A(u8), B(u8),
+}
+
+fn main() {
+    println!("Foo: {}", size_of::<Foo>());
+}
diff --git a/src/test/ui/repr/transparent-enum-too-many-variants.stderr b/src/test/ui/repr/transparent-enum-too-many-variants.stderr
new file mode 100644 (file)
index 0000000..fb44757
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0731]: transparent enum needs exactly one variant, but has 2
+  --> $DIR/transparent-enum-too-many-variants.rs:4:1
+   |
+LL | enum Foo {
+   | ^^^^^^^^ needs exactly one variant, but has 2
+LL |     A(u8), B(u8),
+   |     -      - too many variants in `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0731`.
index 992bcd7977fcfc12931981cf7d89739229bbf3d4..05cabd9e3cd010abe162364718e37ce2c3798d8c 100644 (file)
@@ -2,7 +2,7 @@ fn main() {
     // Make sure primitive type fallback doesn't work in value namespace
     std::mem::size_of(u16);
     //~^ ERROR expected value, found builtin type `u16`
-    //~| ERROR this function takes 0 arguments but 1 argument was supplied
+    //~| ERROR function takes 0 arguments but 1 argument was supplied
 
     // Make sure primitive type fallback doesn't work with global paths
     let _: ::u8;
index d1f685f3e7a6da77d23bba0ba9d913d387fd6f70..6f0d2b045918d6007ac206369c6f52724a4151cf 100644 (file)
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 enum VecWrapper { A(Vec<i32>) }
 
-fn foo(x: VecWrapper) -> usize {
+fn if_guard(x: VecWrapper) -> usize {
     match x {
         VecWrapper::A(v) if { drop(v); false } => 1,
         //~^ ERROR cannot move out of `v` in pattern guard
@@ -8,6 +10,15 @@ fn foo(x: VecWrapper) -> usize {
     }
 }
 
+fn if_let_guard(x: VecWrapper) -> usize {
+    match x {
+        VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        VecWrapper::A(v) => v.len()
+    }
+}
+
 fn main() {
-    foo(VecWrapper::A(vec![107]));
+    if_guard(VecWrapper::A(vec![107]));
+    if_let_guard(VecWrapper::A(vec![107]));
 }
index 6c3d1caf80715d2ad42ecdde2801183a1b87f877..a749361bf30ee10847d64615248d83dbc8332b6c 100644 (file)
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
+  --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
    |
 LL |         VecWrapper::A(v) if { drop(v); false } => 1,
    |                                    ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
+   |
+LL |         VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+   |                                                   ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 571f51c9001202ad99efdfd95832249f635d0dab..827335f6a8494395fbea18f5f8d39c275cf49b78 100644 (file)
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 struct A { a: Box<i32> }
 
-fn foo(n: i32) {
+fn if_guard(n: i32) {
     let x = A { a: Box::new(n) };
     let _y = match x {
         A { a: v } if { drop(v); true } => v,
@@ -9,6 +11,16 @@ fn foo(n: i32) {
     };
 }
 
+fn if_let_guard(n: i32) {
+    let x = A { a: Box::new(n) };
+    let _y = match x {
+        A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        _ => Box::new(0),
+    };
+}
+
 fn main() {
-    foo(107);
+    if_guard(107);
+    if_let_guard(107);
 }
index d1204bc26011f815c82e31ea442ca07a5eb81436..9285492b224503305299266bc8cbac4ca2d692dd 100644 (file)
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
    |
 LL |         A { a: v } if { drop(v); true } => v,
    |                              ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
+   |
+LL |         A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+   |                                             ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index fefb84de729fed481dec362ebebbe72bb983872d..28b3f76c9d536805fb957bc625971530cb926684 100644 (file)
@@ -1,10 +1,14 @@
 // run-pass
+// revisions: default mir-opt
+//[default] compile-flags: -Zinline-mir=no
+//[mir-opt] compile-flags: -Zmir-opt-level=4
 
 use std::panic::Location;
 
 struct Foo;
 
 impl Foo {
+    #[inline(always)]
     #[track_caller]
     fn check_loc(&self, line: u32, col: u32) -> &Self {
         let loc = Location::caller();
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs
new file mode 100644 (file)
index 0000000..b5f19e4
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+    fn a(self) -> i32;
+}
+
+impl Tr for () {
+    fn a(self) -> i32 { 42 }
+}
+
+const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+    x(())
+}
+
+const _: () = assert!(need_const_closure(Tr::a) == 42);
+//~^ ERROR: the trait bound
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
new file mode 100644 (file)
index 0000000..4470e28
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied in `fn(()) -> i32 {<() as Tr>::a}`
+  --> $DIR/const-closure-trait-method-fail.rs:16:42
+   |
+LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
+   |                       ------------------ ^^^^^ within `fn(()) -> i32 {<() as Tr>::a}`, the trait `~const Tr` is not implemented for `()`
+   |                       |
+   |                       required by a bound introduced by this call
+   |
+note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
+  --> $DIR/const-closure-trait-method-fail.rs:16:42
+   |
+LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
+   |                                          ^^^^^
+   = note: required because it appears within the type `fn(()) -> i32 {<() as Tr>::a}`
+note: required by a bound in `need_const_closure`
+  --> $DIR/const-closure-trait-method-fail.rs:12:32
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `need_const_closure`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs
new file mode 100644 (file)
index 0000000..3e6d190
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+    fn a(self) -> i32;
+}
+
+impl const Tr for () {
+    fn a(self) -> i32 { 42 }
+}
+
+const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+    x(())
+}
+
+const _: () = assert!(need_const_closure(Tr::a) == 42);
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
new file mode 100644 (file)
index 0000000..8cdb08e
--- /dev/null
@@ -0,0 +1,137 @@
+// edition:2018
+// aux-build:edition-lint-infer-outlives-macro.rs
+// run-rustfix
+
+#![deny(explicit_outlives_requirements)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate edition_lint_infer_outlives_macro;
+
+// Test that the lint does not fire if the predicate is from the local crate,
+// but all the bounds are from an external macro.
+macro_rules! make_foo {
+    ($a:tt) => {
+        struct Foo<$a, 'b: $a> {
+            foo: &$a &'b (),
+        }
+
+        struct FooWhere<$a, 'b> where 'b: $a {
+            foo: &$a &'b (),
+        }
+    }
+}
+
+gimme_a! {make_foo!}
+
+struct Bar<'a, 'b> {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+struct BarWhere<'a, 'b> {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+// Test that the lint *does* fire if the predicate is contained in a local macro.
+mod everything_inside {
+    macro_rules! m {
+        ('b: 'a) => {
+            struct Foo<'a, 'b>(&'a &'b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<'a, 'b>(&'a &'b ()) ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, ;
+            //~^ ERROR: outlives requirements can be inferred
+        };
+    }
+    m!('b: 'a);
+}
+
+mod inner_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: 'a) => {
+            struct Foo<'a, $b>(&'a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<'a, $b>(&'a &$b ()) ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, $b>(&'a &$b ()) where (): Sized, ;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
+mod outer_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ('b: $a:lifetime) => {
+            struct Foo<$a, 'b: $a>(&$a &'b ());
+            struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
+            struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod both_lifetimes_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: $a:lifetime) => {
+            struct Foo<$a, $b: $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside_with_tt_inner {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+// FIXME: These should be consistent.
+mod everything_outside_with_tt_outer {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:tt) => {
+            struct Foo<$a, $b >(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside_with_tt_both {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:tt) => {
+            struct Foo<$a, $b >(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where ;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, ;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
+fn main() {}
index d7a832831c1d91cc916021ab172decb757d38420..647906c2dc228366e713dc40217f98e907d5a8b1 100644 (file)
@@ -1,18 +1,22 @@
 // edition:2018
 // aux-build:edition-lint-infer-outlives-macro.rs
-
-// Test that the lint does not fire if the where predicate
-// is from the local crate, but all the bounds are from an
-// external macro.
+// run-rustfix
 
 #![deny(explicit_outlives_requirements)]
+#![allow(dead_code)]
 
 #[macro_use]
 extern crate edition_lint_infer_outlives_macro;
 
+// Test that the lint does not fire if the predicate is from the local crate,
+// but all the bounds are from an external macro.
 macro_rules! make_foo {
     ($a:tt) => {
-        struct Foo<$a, 'b> where 'b: $a {
+        struct Foo<$a, 'b: $a> {
+            foo: &$a &'b (),
+        }
+
+        struct FooWhere<$a, 'b> where 'b: $a {
             foo: &$a &'b (),
         }
     }
@@ -25,4 +29,109 @@ struct Bar<'a, 'b: 'a> {
     bar: &'a &'b (),
 }
 
+struct BarWhere<'a, 'b> where 'b: 'a {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+// Test that the lint *does* fire if the predicate is contained in a local macro.
+mod everything_inside {
+    macro_rules! m {
+        ('b: 'a) => {
+            struct Foo<'a, 'b: 'a>(&'a &'b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<'a, 'b>(&'a &'b ()) where 'b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, 'b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+        };
+    }
+    m!('b: 'a);
+}
+
+mod inner_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: 'a) => {
+            struct Foo<'a, $b: 'a>(&'a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<'a, $b>(&'a &$b ()) where $b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<'a, $b>(&'a &$b ()) where (): Sized, $b: 'a;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
+mod outer_lifetime_outside_colon_inside {
+    macro_rules! m {
+        ('b: $a:lifetime) => {
+            struct Foo<$a, 'b: $a>(&$a &'b ());
+            struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
+            struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod both_lifetimes_outside_colon_inside {
+    macro_rules! m {
+        ($b:lifetime: $a:lifetime) => {
+            struct Foo<$a, $b: $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside_with_tt_inner {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:lifetime) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+// FIXME: These should be consistent.
+mod everything_outside_with_tt_outer {
+    macro_rules! m {
+        ($b:lifetime $colon:tt $a:tt) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+        }
+    }
+    m!('b: 'a);
+}
+
+mod everything_outside_with_tt_both {
+    macro_rules! m {
+        ($b:tt $colon:tt $a:tt) => {
+            struct Foo<$a, $b $colon $a>(&$a &$b ());
+            //~^ ERROR: outlives requirements can be inferred
+            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+            //~^ ERROR: outlives requirements can be inferred
+            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+            //~^ ERROR: outlives requirements can be inferred
+        }
+    }
+    m!('b: 'a);
+}
+
 fn main() {}
index 553b1cd976ad6a114a10ce5dcc15770650ee10b3..734ae687978936e022a177b7be164aee75d60f4a 100644 (file)
 error: outlives requirements can be inferred
-  --> $DIR/edition-lint-infer-outlives-macro.rs:23:18
+  --> $DIR/edition-lint-infer-outlives-macro.rs:27:18
    |
 LL | struct Bar<'a, 'b: 'a> {
    |                  ^^^^ help: remove this bound
    |
 note: the lint level is defined here
-  --> $DIR/edition-lint-infer-outlives-macro.rs:8:9
+  --> $DIR/edition-lint-infer-outlives-macro.rs:5:9
    |
 LL | #![deny(explicit_outlives_requirements)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:32:24
+   |
+LL | struct BarWhere<'a, 'b> where 'b: 'a {
+   |                        ^^^^^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:41:30
+   |
+LL |             struct Foo<'a, 'b: 'a>(&'a &'b ());
+   |                              ^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:43:44
+   |
+LL |             struct Bar<'a, 'b>(&'a &'b ()) where 'b: 'a;
+   |                                            ^^^^^^^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:45:61
+   |
+LL |             struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, 'b: 'a;
+   |                                                             ^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:55:30
+   |
+LL |             struct Foo<'a, $b: 'a>(&'a &$b ());
+   |                              ^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:57:44
+   |
+LL |             struct Bar<'a, $b>(&'a &$b ()) where $b: 'a;
+   |                                            ^^^^^^^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:59:61
+   |
+LL |             struct Baz<'a, $b>(&'a &$b ()) where (): Sized, $b: 'a;
+   |                                                             ^^^^^^ help: remove this bound
+...
+LL |     m!('b: 'a);
+   |     ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:114:31
+   |
+LL |             struct Foo<$a, $b $colon $a>(&$a &$b ());
+   |                               ^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:126:31
+   |
+LL |             struct Foo<$a, $b $colon $a>(&$a &$b ());
+   |                               ^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:128:50
+   |
+LL |             struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
+   |                                                  ^^^^^^^^^^^^ help: remove this bound
+
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:130:61
+   |
+LL |             struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
+   |                                                             ^^^^^^^^^^^^ help: remove this bound
+
+error: aborting due to 12 previous errors
 
index e4ec9f875765a35d3f1c88dddfacb4dcf35c02f8..570328fc211f98b052a9ae7185d053312fb2fbcd 100644 (file)
@@ -1,18 +1,24 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:53:24
    |
-LL | fn deref_mut_field1(x: Own<Point>) {
-   |                     - help: consider changing this to be mutable: `mut x`
 LL |     let __isize = &mut x.y;
    |                        ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn deref_mut_field1(mut x: Own<Point>) {
+   |                     +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:65:10
    |
-LL | fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
-   |                               ----------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
 LL |     &mut x.y
    |          ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn deref_extend_mut_field1(x: &mut Own<Point>) -> &mut isize {
+   |                               ~~~~~~~~~~~~~~~
 
 error[E0499]: cannot borrow `*x` as mutable more than once at a time
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:78:19
@@ -27,18 +33,24 @@ LL |     use_mut(_x);
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:5
    |
-LL | fn assign_field1<'a>(x: Own<Point>) {
-   |                      - help: consider changing this to be mutable: `mut x`
 LL |     x.y = 3;
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn assign_field1<'a>(mut x: Own<Point>) {
+   |                      +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:92:5
    |
-LL | fn assign_field2<'a>(x: &'a Own<Point>) {
-   |                         -------------- help: consider changing this to be a mutable reference: `&'a mut Own<Point>`
 LL |     x.y = 3;
    |     ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn assign_field2<'a>(x: &'a mut Own<Point>) {
+   |                         ~~~~~~~~~~~~~~~~~~
 
 error[E0499]: cannot borrow `*x` as mutable more than once at a time
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:101:5
@@ -53,34 +65,46 @@ LL |     use_mut(_p);
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:109:5
    |
-LL | fn deref_mut_method1(x: Own<Point>) {
-   |                      - help: consider changing this to be mutable: `mut x`
 LL |     x.set(0, 0);
    |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn deref_mut_method1(mut x: Own<Point>) {
+   |                      +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5
    |
-LL | fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
-   |                                ----------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
 LL |     x.y_mut()
    |     ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn deref_extend_mut_method1(x: &mut Own<Point>) -> &mut isize {
+   |                                ~~~~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6
    |
-LL | fn assign_method1<'a>(x: Own<Point>) {
-   |                       - help: consider changing this to be mutable: `mut x`
 LL |     *x.y_mut() = 3;
    |      ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn assign_method1<'a>(mut x: Own<Point>) {
+   |                       +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6
    |
-LL | fn assign_method2<'a>(x: &'a Own<Point>) {
-   |                          -------------- help: consider changing this to be a mutable reference: `&'a mut Own<Point>`
 LL |     *x.y_mut() = 3;
    |      ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn assign_method2<'a>(x: &'a mut Own<Point>) {
+   |                          ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 10 previous errors
 
index 3ebfba7e4debe7d0f299721f0902b9afd1383200..3fed7b3f4dcf3afd2da5944de1cc0278429df860 100644 (file)
@@ -1,34 +1,46 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:29:25
    |
-LL | fn deref_mut1(x: Own<isize>) {
-   |               - help: consider changing this to be mutable: `mut x`
 LL |     let __isize = &mut *x;
    |                         ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn deref_mut1(mut x: Own<isize>) {
+   |               +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:41:11
    |
-LL | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
-   |                             -------------- help: consider changing this to be a mutable reference: `&'a mut Own<isize>`
 LL |     &mut **x
    |           ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn deref_extend_mut1<'a>(x: &'a mut Own<isize>) -> &'a mut isize {
+   |                             ~~~~~~~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6
    |
-LL | fn assign1<'a>(x: Own<isize>) {
-   |                - help: consider changing this to be mutable: `mut x`
 LL |     *x = 3;
    |      ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn assign1<'a>(mut x: Own<isize>) {
+   |                +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:53:6
    |
-LL | fn assign2<'a>(x: &'a Own<isize>) {
-   |                   -------------- help: consider changing this to be a mutable reference: `&'a mut Own<isize>`
 LL |     **x = 3;
    |      ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn assign2<'a>(x: &'a mut Own<isize>) {
+   |                   ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
index 6b43801b5e074fbdd4c1e3a80b57791b08e6eed2..48b42bc78253f59842a5fe00a4416b3bea2e24b4 100644 (file)
@@ -13,18 +13,24 @@ LL |         f((Box::new(|| {})))
 error[E0596]: cannot borrow `*f` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:25:5
    |
-LL | fn test2<F>(f: &F) where F: FnMut() {
-   |                -- help: consider changing this to be a mutable reference: `&mut F`
 LL |     (*f)();
    |     ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn test2<F>(f: &mut F) where F: FnMut() {
+   |                ~~~~~~
 
 error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5
    |
-LL | fn test4(f: &Test) {
-   |             ----- help: consider changing this to be a mutable reference: `&mut Test<'_>`
 LL |     f.f.call_mut(())
    |     ^^^^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn test4(f: &mut Test<'_>) {
+   |             ~~~~~~~~~~~~~
 
 error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13
index 1864f5de108cd10911c221588cb43ea1ff85bf08..2a842f5a2a9f8f6ab6688a7572e38a4a791d6585 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-call-method-from-mut-aliasable.rs:17:5
    |
-LL | fn b(x: &Foo) {
-   |         ---- help: consider changing this to be a mutable reference: `&mut Foo`
-LL |     x.f();
 LL |     x.h();
    |     ^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn b(x: &mut Foo) {
+   |         ~~~~~~~~
 
 error: aborting due to previous error
 
index 1f5d8bd32bb57faf27df0e2c8cdca481ca30d15a..1df19deb12f6b59955b0d862f5a258a3960b64c5 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-fn-in-const-b.rs:7:9
    |
-LL |     fn broken(x: &Vec<String>) {
-   |                  ------------ help: consider changing this to be a mutable reference: `&mut Vec<String>`
 LL |         x.push(format!("this is broken"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn broken(x: &mut Vec<String>) {
+   |                  ~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index cc43f6d0928dadb51e94e829793f837680a01b82..b6517e0b3095dc3430306bf7aa3373d544cc234a 100644 (file)
@@ -1,20 +1,24 @@
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-object-mutability.rs:8:5
    |
-LL | fn borrowed_receiver(x: &dyn Foo) {
-   |                         -------- help: consider changing this to be a mutable reference: `&mut dyn Foo`
-LL |     x.borrowed();
 LL |     x.borrowed_mut();
    |     ^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn borrowed_receiver(x: &mut dyn Foo) {
+   |                         ~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
   --> $DIR/borrowck-object-mutability.rs:18:5
    |
-LL | fn owned_receiver(x: Box<dyn Foo>) {
-   |                   - help: consider changing this to be mutable: `mut x`
-LL |     x.borrowed();
 LL |     x.borrowed_mut();
    |     ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn owned_receiver(mut x: Box<dyn Foo>) {
+   |                   +++
 
 error: aborting due to 2 previous errors
 
index 5b8fc71384efe05659497f6a2eae3d93d6a6681d..9227ee482dfa554e4ada93fd38b16d798ebb7130 100644 (file)
@@ -4,8 +4,8 @@ fn bar(x, y: usize) {} //~ ERROR expected one of
 
 fn main() {
     foo(Some(42), 2);
-    foo(Some(42), 2, ""); //~ ERROR this function takes
+    foo(Some(42), 2, ""); //~ ERROR function takes
     bar("", ""); //~ ERROR mismatched types
     bar(1, 2);
-    bar(1, 2, 3); //~ ERROR this function takes
+    bar(1, 2, 3); //~ ERROR function takes
 }
index 5b9861da6e8544079bcb506ddc7e683f4d76788e..db96ae223d92b941884b6a321f03609d206358fb 100644 (file)
@@ -9,9 +9,9 @@ fn generic<T>(self, _: T) { }
 
 fn main() {
     let _: Result<(), String> = Ok(); //~ ERROR this enum variant takes
-    foo(); //~ ERROR this function takes
-    foo(()); //~ ERROR this function takes
-    bar(); //~ ERROR this function takes
-    S.baz(); //~ ERROR this function takes
-    S.generic::<()>(); //~ ERROR this function takes
+    foo(); //~ ERROR function takes
+    foo(()); //~ ERROR function takes
+    bar(); //~ ERROR function takes
+    S.baz(); //~ ERROR this method takes
+    S.generic::<()>(); //~ ERROR this method takes
 }
index 48a2e763af615a23e15104e5ffcf57f0c127cf30..ef4d732b51d2dbc1d2bdb66d3b4192608584dda1 100644 (file)
@@ -59,7 +59,7 @@ help: provide the argument
 LL |     bar(());
    |        ~~~~
 
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:15:7
    |
 LL |     S.baz();
@@ -75,7 +75,7 @@ help: provide the argument
 LL |     S.baz(());
    |          ~~~~
 
-error[E0061]: this function takes 1 argument but 0 arguments were supplied
+error[E0061]: this method takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:16:7
    |
 LL |     S.generic::<()>();
index 8a7c504f0053bdaa94a9ba5ebcc036166d87f189..96ce4d5bc6c338f83ee658b0f77f3c32279618c9 100644 (file)
@@ -1,26 +1,35 @@
 error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
   --> $DIR/mut-arg-hint.rs:3:9
    |
-LL |     fn foo(mut a: &String) {
-   |                   ------- help: consider changing this to be a mutable reference: `&mut String`
 LL |         a.push_str("bar");
    |         ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn foo(mut a: &mut String) {
+   |                   ~~~~~~~~~~~
 
 error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
   --> $DIR/mut-arg-hint.rs:8:5
    |
-LL | pub fn foo<'a>(mut a: &'a String) {
-   |                       ---------- help: consider changing this to be a mutable reference: `&'a mut String`
 LL |     a.push_str("foo");
    |     ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | pub fn foo<'a>(mut a: &'a mut String) {
+   |                       ~~~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference
   --> $DIR/mut-arg-hint.rs:15:9
    |
-LL |     pub fn foo(mut a: &String) {
-   |                       ------- help: consider changing this to be a mutable reference: `&mut String`
 LL |         a.push_str("foo");
    |         ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     pub fn foo(mut a: &mut String) {
+   |                       ~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
index 408732fe944fe1c558c52aa3d78e0f05d3f8fe23..104bddd076ec18f5da6d703f959d51fbe42a0068 100644 (file)
@@ -15,8 +15,10 @@ fn to_string(&self) -> String {
     }
 }
 
-impl<B: ?Sized> Display for Cow<'_, B> { //~ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { //~ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
+impl<B: ?Sized> Display for Cow<'_, B> {
+    //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277]
         write!(f, "foo")
     }
 }
index fd34a59d2bd6df2252a7a238d155f7d6499b2e19..be6f04ae62a0d247ccce29f54176a8b5fdff63a5 100644 (file)
@@ -1,12 +1,8 @@
 error[E0277]: the trait bound `B: Clone` is not satisfied
-  --> $DIR/issue-79224.rs:18:1
+  --> $DIR/issue-79224.rs:18:17
    |
-LL | / impl<B: ?Sized> Display for Cow<'_, B> {
-LL | |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-LL | |         write!(f, "foo")
-LL | |     }
-LL | | }
-   | |_^ the trait `Clone` is not implemented for `B`
+LL | impl<B: ?Sized> Display for Cow<'_, B> {
+   |                 ^^^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
@@ -15,12 +11,10 @@ LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> {
    |                +++++++++++++++++++
 
 error[E0277]: the trait bound `B: Clone` is not satisfied
-  --> $DIR/issue-79224.rs:19:5
+  --> $DIR/issue-79224.rs:20:12
    |
-LL | /     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-LL | |         write!(f, "foo")
-LL | |     }
-   | |_____^ the trait `Clone` is not implemented for `B`
+LL |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+   |            ^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
index 079230b2a3160e5462cb70d72b0655235be734a2..89a8425f5e78a6adbd6a451d27f3d6f76fbc491b 100644 (file)
@@ -132,5 +132,5 @@ LL | #[stable(feature = "a", since = "1.0.0")]
 
 error: aborting due to 20 previous errors
 
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0711.
 For more information about an error, try `rustc --explain E0539`.
index 15900bef7f62458493a9a04fb0ae4c7ad900fbf4..7d9ff2dfb4d986213baa9c344a6787c15abc95e0 100644 (file)
@@ -41,8 +41,8 @@ ast-stats-1 - Wild                      88 ( 1.2%)             1
 ast-stats-1 - Ident                    440 ( 5.9%)             5
 ast-stats-1 PathSegment              720 ( 9.7%)            30            24
 ast-stats-1 Ty                       896 (12.1%)            14            64
-ast-stats-1 - Rptr                      64 ( 0.9%)             1
 ast-stats-1 - Ptr                       64 ( 0.9%)             1
+ast-stats-1 - Ref                       64 ( 0.9%)             1
 ast-stats-1 - ImplicitSelf             128 ( 1.7%)             2
 ast-stats-1 - Path                     640 ( 8.6%)            10
 ast-stats-1 Item                   1_656 (22.3%)             9           184
@@ -100,8 +100,8 @@ ast-stats-2 - Lit                      144 ( 1.8%)             2
 ast-stats-2 - Block                    216 ( 2.7%)             3
 ast-stats-2 PathSegment              792 ( 9.8%)            33            24
 ast-stats-2 Ty                       896 (11.0%)            14            64
-ast-stats-2 - Rptr                      64 ( 0.8%)             1
 ast-stats-2 - Ptr                       64 ( 0.8%)             1
+ast-stats-2 - Ref                       64 ( 0.8%)             1
 ast-stats-2 - ImplicitSelf             128 ( 1.6%)             2
 ast-stats-2 - Path                     640 ( 7.9%)            10
 ast-stats-2 Item                   2_024 (25.0%)            11           184
@@ -154,7 +154,7 @@ hir-stats GenericParam             400 ( 4.4%)             5            80
 hir-stats Generics                 560 ( 6.2%)            10            56
 hir-stats Ty                       720 ( 8.0%)            15            48
 hir-stats - Ptr                       48 ( 0.5%)             1
-hir-stats - Rptr                      48 ( 0.5%)             1
+hir-stats - Ref                       48 ( 0.5%)             1
 hir-stats - Path                     624 ( 6.9%)            13
 hir-stats Expr                     768 ( 8.5%)            12            64
 hir-stats - Path                      64 ( 0.7%)             1
index 5403b8d6d2871ae65a8f548ff6e39e2e2b9a1659..f5931a1baea11d83872b2d4ce86e55ce3f4b31d7 100644 (file)
@@ -6,7 +6,7 @@ fn main() {
     let _: Option<(i32, bool)> = Some(1, 2);
     //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
     int_bool(1, 2);
-    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~^ ERROR function takes 1 argument but 2 arguments were supplied
 
     let _: Option<(i8,)> = Some();
     //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
index 66e53f9ce2c80bef49c642f16571fc521fb0f458..f913995d7e28bd385a9858c92b6f55844eec3af8 100644 (file)
@@ -5,11 +5,11 @@
 
 fn main() {
     let _: Result<(i32, i8), ()> = Ok((1, 2));
-    //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+    //~^ ERROR enum variant takes 1 argument but 2 arguments were supplied
     let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
-    //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied
+    //~^ ERROR enum variant takes 1 argument but 3 arguments were supplied
     let _: Option<()> = Some(());
-    //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+    //~^ ERROR enum variant takes 1 argument but 0 arguments were supplied
 
     let _: Option<(i32,)> = Some((3,));
     //~^ ERROR mismatched types
@@ -17,9 +17,9 @@ fn main() {
     let _: Option<(i32,)> = Some((3,));
     //~^ ERROR mismatched types
 
-    two_ints((1, 2)); //~ ERROR this function takes 1 argument
+    two_ints((1, 2)); //~ ERROR function takes 1 argument
 
-    with_generic((3, 4)); //~ ERROR this function takes 1 argument
+    with_generic((3, 4)); //~ ERROR function takes 1 argument
 }
 
 fn two_ints(_: (i32, i32)) {
@@ -28,6 +28,6 @@ fn two_ints(_: (i32, i32)) {
 fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
     if false {
         // test generics/bound handling
-        with_generic((a, b)); //~ ERROR this function takes 1 argument
+        with_generic((a, b)); //~ ERROR function takes 1 argument
     }
 }
index a15bff07ebfe6766e2a99ea097f7d23ea7397215..1c65407b3955e8551b27a9be658e5875e0ebb33d 100644 (file)
@@ -5,11 +5,11 @@
 
 fn main() {
     let _: Result<(i32, i8), ()> = Ok(1, 2);
-    //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+    //~^ ERROR enum variant takes 1 argument but 2 arguments were supplied
     let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
-    //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied
+    //~^ ERROR enum variant takes 1 argument but 3 arguments were supplied
     let _: Option<()> = Some();
-    //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+    //~^ ERROR enum variant takes 1 argument but 0 arguments were supplied
 
     let _: Option<(i32,)> = Some(3);
     //~^ ERROR mismatched types
@@ -17,9 +17,9 @@ fn main() {
     let _: Option<(i32,)> = Some((3));
     //~^ ERROR mismatched types
 
-    two_ints(1, 2); //~ ERROR this function takes 1 argument
+    two_ints(1, 2); //~ ERROR function takes 1 argument
 
-    with_generic(3, 4); //~ ERROR this function takes 1 argument
+    with_generic(3, 4); //~ ERROR function takes 1 argument
 }
 
 fn two_ints(_: (i32, i32)) {
@@ -28,6 +28,6 @@ fn two_ints(_: (i32, i32)) {
 fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
     if false {
         // test generics/bound handling
-        with_generic(a, b); //~ ERROR this function takes 1 argument
+        with_generic(a, b); //~ ERROR function takes 1 argument
     }
 }
index c8499010d6896365bccf42f5689638ca088156e0..3ed9dbf4abbc63118d9ca64344ec23a81df6f7d7 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
+error[E0061]: enum variant takes 1 argument but 2 arguments were supplied
   --> $DIR/args-instead-of-tuple.rs:7:36
    |
 LL |     let _: Result<(i32, i8), ()> = Ok(1, 2);
@@ -11,7 +11,7 @@ help: wrap these arguments in parentheses to construct a tuple
 LL |     let _: Result<(i32, i8), ()> = Ok((1, 2));
    |                                       +    +
 
-error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
+error[E0061]: enum variant takes 1 argument but 3 arguments were supplied
   --> $DIR/args-instead-of-tuple.rs:9:46
    |
 LL |     let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
@@ -71,7 +71,7 @@ help: use a trailing comma to create a tuple with one element
 LL |     let _: Option<(i32,)> = Some((3,));
    |                                    +
 
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
   --> $DIR/args-instead-of-tuple.rs:20:5
    |
 LL |     two_ints(1, 2);
@@ -87,7 +87,7 @@ help: wrap these arguments in parentheses to construct a tuple
 LL |     two_ints((1, 2));
    |              +    +
 
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
   --> $DIR/args-instead-of-tuple.rs:22:5
    |
 LL |     with_generic(3, 4);
@@ -103,7 +103,7 @@ help: wrap these arguments in parentheses to construct a tuple
 LL |     with_generic((3, 4));
    |                  +    +
 
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
   --> $DIR/args-instead-of-tuple.rs:31:9
    |
 LL |         with_generic(a, b);
diff --git a/src/test/ui/suggestions/bad-hex-float-lit.rs b/src/test/ui/suggestions/bad-hex-float-lit.rs
new file mode 100644 (file)
index 0000000..cd6fdbd
--- /dev/null
@@ -0,0 +1,13 @@
+fn main() {
+    let _f: f32 = 0xAAf32;
+    //~^ ERROR mismatched types
+    //~| HELP rewrite this
+
+    let _f: f32 = 0xAB_f32;
+    //~^ ERROR mismatched types
+    //~| HELP rewrite this
+
+    let _f: f64 = 0xFF_f64;
+    //~^ ERROR mismatched types
+    //~| HELP rewrite this
+}
diff --git a/src/test/ui/suggestions/bad-hex-float-lit.stderr b/src/test/ui/suggestions/bad-hex-float-lit.stderr
new file mode 100644 (file)
index 0000000..bc09abb
--- /dev/null
@@ -0,0 +1,48 @@
+error[E0308]: mismatched types
+  --> $DIR/bad-hex-float-lit.rs:2:19
+   |
+LL |     let _f: f32 = 0xAAf32;
+   |             ---   ^^^^^^^ expected `f32`, found integer
+   |             |
+   |             expected due to this
+   |
+help: rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float
+   |
+LL |     let _f: f32 = 0xAA as f32;
+   |                   ~~~~~~~~~~~
+LL |     let _f: f32 = 170_f32;
+   |                   ~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/bad-hex-float-lit.rs:6:19
+   |
+LL |     let _f: f32 = 0xAB_f32;
+   |             ---   ^^^^^^^^ expected `f32`, found integer
+   |             |
+   |             expected due to this
+   |
+help: rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float
+   |
+LL |     let _f: f32 = 0xAB as f32;
+   |                   ~~~~~~~~~~~
+LL |     let _f: f32 = 171_f32;
+   |                   ~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/bad-hex-float-lit.rs:10:19
+   |
+LL |     let _f: f64 = 0xFF_f64;
+   |             ---   ^^^^^^^^ expected `f64`, found integer
+   |             |
+   |             expected due to this
+   |
+help: rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float
+   |
+LL |     let _f: f64 = 0xFF as f64;
+   |                   ~~~~~~~~~~~
+LL |     let _f: f64 = 255_f64;
+   |                   ~~~~~~~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 288d6c699f59a03a38335fea9aef48938e33288b..c1c969b90e4dbf89fc087bbbcd992cc432105d34 100644 (file)
@@ -1,5 +1,5 @@
 fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
-     t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
+     t.min().unwrap() //~ ERROR the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
 }
 
 fn main() {
index 7791b308d5d0e597a4263c6afb85570b07f1158a..f7f7902c17d16718812d4efda382f9f16b43605d 100644 (file)
@@ -1,13 +1,13 @@
-error: the `min` method cannot be invoked on a trait object
+error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
   --> $DIR/imm-ref-trait-object.rs:2:8
    |
 LL |      t.min().unwrap()
    |        ^^^
-  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
-   = note: this has a `Sized` requirement
+help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
    |
-   = note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
+LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
+   |             +++
 
 error: aborting due to previous error
 
index 9839e973bdfe44fa106e68d75fbbd8d6cde8375f..a1a51c4814e8fc980918e2c5735859d52f39d0a8 100644 (file)
@@ -60,4 +60,9 @@ fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
     //~| ERROR missing lifetime specifier
 }
 
+// This must not err, as the `&` actually resolves to `'a`.
+fn resolved_anonymous<'a, T>(f: impl Fn(&'a str) -> &T) {
+    f("f")
+}
+
 fn main() {}
index b7601a548b9981cf5540f43b7866e3f6c9084722..e3fa22a8f66f4123a0afe3dcb44bed96c9aafc6b 100644 (file)
@@ -1,9 +1,13 @@
 // The purpose of this test is not to validate the output of the compiler.
 // Instead, it ensures the suggestion is generated without performing an arithmetic overflow.
 
+struct S;
+impl S {
+    fn foo(&self) {}
+}
 fn main() {
-    let x = not_found; //~ ERROR cannot find value `not_found` in this scope
-    simd_gt::<()>(x);
+    let x = S;
+    foo::<()>(x);
     //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
-    //~| ERROR cannot find function `simd_gt` in this scope
+    //~| ERROR cannot find function `foo` in this scope
 }
index 79812a2985ef9444f0d46f15a698e19916fbeed3..602a01828b28b331626e1151a4d2639f8abe0d5b 100644 (file)
@@ -1,30 +1,30 @@
-error[E0425]: cannot find value `not_found` in this scope
-  --> $DIR/issue-104287.rs:5:13
-   |
-LL |     let x = not_found;
-   |             ^^^^^^^^^ not found in this scope
-
 error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/issue-104287.rs:6:5
+  --> $DIR/issue-104287.rs:10:5
    |
-LL |     simd_gt::<()>(x);
-   |     ^^^^^^^------ help: remove these generics
+LL |     foo::<()>(x);
+   |     ^^^------ help: remove these generics
    |     |
    |     expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/issue-104287.rs:6:8
+   |
+LL |     fn foo(&self) {}
+   |        ^^^
 
-error[E0425]: cannot find function `simd_gt` in this scope
-  --> $DIR/issue-104287.rs:6:5
+error[E0425]: cannot find function `foo` in this scope
+  --> $DIR/issue-104287.rs:10:5
    |
-LL |     simd_gt::<()>(x);
-   |     ^^^^^^^ not found in this scope
+LL |     foo::<()>(x);
+   |     ^^^ not found in this scope
    |
-help: use the `.` operator to call the method `SimdPartialOrd::simd_gt` on `[type error]`
+help: use the `.` operator to call the method `foo` on `&S`
    |
-LL -     simd_gt::<()>(x);
-LL +     x.simd_gt();
+LL -     foo::<()>(x);
+LL +     x.foo();
    |
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0107, E0425.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/issue-105645.rs b/src/test/ui/suggestions/issue-105645.rs
new file mode 100644 (file)
index 0000000..681ce1c
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let mut buf = [0u8; 50];
+    let mut bref = buf.as_slice();
+    foo(&mut bref);
+    //~^ ERROR 4:9: 4:18: the trait bound `&[u8]: std::io::Write` is not satisfied [E0277]
+}
+
+fn foo(_: &mut impl std::io::Write) {}
diff --git a/src/test/ui/suggestions/issue-105645.stderr b/src/test/ui/suggestions/issue-105645.stderr
new file mode 100644 (file)
index 0000000..895f5ff
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `&[u8]: std::io::Write` is not satisfied
+  --> $DIR/issue-105645.rs:4:9
+   |
+LL |     foo(&mut bref);
+   |     --- ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&[u8]`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `std::io::Write` is implemented for `&mut [u8]`
+note: required by a bound in `foo`
+  --> $DIR/issue-105645.rs:8:21
+   |
+LL | fn foo(_: &mut impl std::io::Write) {}
+   |                     ^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-106443-sugg-clone-for-arg.rs b/src/test/ui/suggestions/issue-106443-sugg-clone-for-arg.rs
new file mode 100644 (file)
index 0000000..48efdb8
--- /dev/null
@@ -0,0 +1,23 @@
+#[derive(Clone)]
+struct S;
+
+// without Clone
+struct T;
+
+fn foo(_: S) {}
+
+fn test1() {
+    let s = &S;
+    foo(s); //~ ERROR mismatched types
+}
+
+fn bar(_: T) {}
+fn test2() {
+    let t = &T;
+    bar(t); //~ ERROR mismatched types
+}
+
+fn main() {
+    test1();
+    test2();
+}
diff --git a/src/test/ui/suggestions/issue-106443-sugg-clone-for-arg.stderr b/src/test/ui/suggestions/issue-106443-sugg-clone-for-arg.stderr
new file mode 100644 (file)
index 0000000..1e66fe3
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-106443-sugg-clone-for-arg.rs:11:9
+   |
+LL |     foo(s);
+   |     --- ^ expected struct `S`, found `&S`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/issue-106443-sugg-clone-for-arg.rs:7:4
+   |
+LL | fn foo(_: S) {}
+   |    ^^^ ----
+help: consider using clone here
+   |
+LL |     foo(s.clone());
+   |          ++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-106443-sugg-clone-for-arg.rs:17:9
+   |
+LL |     bar(t);
+   |     --- ^ expected struct `T`, found `&T`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/issue-106443-sugg-clone-for-arg.rs:14:4
+   |
+LL | fn bar(_: T) {}
+   |    ^^^ ----
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/issue-106443-sugg-clone-for-bound.rs b/src/test/ui/suggestions/issue-106443-sugg-clone-for-bound.rs
new file mode 100644 (file)
index 0000000..3b2e316
--- /dev/null
@@ -0,0 +1,20 @@
+#[derive(Clone)]
+struct S;
+
+trait X {}
+
+impl X for S {}
+
+fn foo<T: X>(_: T) {}
+fn bar<T: X>(s: &T) {
+    foo(s); //~ ERROR the trait bound `&T: X` is not satisfied
+}
+
+fn bar_with_clone<T: X + Clone>(s: &T) {
+    foo(s); //~ ERROR the trait bound `&T: X` is not satisfied
+}
+
+fn main() {
+    let s = &S;
+    bar(s);
+}
diff --git a/src/test/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr b/src/test/ui/suggestions/issue-106443-sugg-clone-for-bound.stderr
new file mode 100644 (file)
index 0000000..8607917
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0277]: the trait bound `&T: X` is not satisfied
+  --> $DIR/issue-106443-sugg-clone-for-bound.rs:10:9
+   |
+LL |     foo(s);
+   |         ^ the trait `X` is not implemented for `&T`
+   |
+help: consider further restricting this bound
+   |
+LL | fn bar<T: X + Clone>(s: &T) {
+   |             +++++++
+help: consider using clone here
+   |
+LL |     foo(s.clone());
+   |          ++++++++
+
+error[E0277]: the trait bound `&T: X` is not satisfied
+  --> $DIR/issue-106443-sugg-clone-for-bound.rs:14:9
+   |
+LL |     foo(s);
+   |         ^ the trait `X` is not implemented for `&T`
+   |
+help: consider using clone here
+   |
+LL |     foo(s.clone());
+   |          ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 2f31193e4a4a2b1717bf3d1bd5acd45e9e21a74b..de35aa5b186b5af82a94790bdb4f6876b814c367 100644 (file)
@@ -1,20 +1,24 @@
 error[E0594]: cannot assign to `*input`, which is behind a `&` reference
   --> $DIR/issue-68049-2.rs:9:7
    |
-LL |   fn example(&self, input: &i32); // should suggest here
-   |                            ---- help: consider changing that to be a mutable reference: `&mut i32`
-...
 LL |       *input = self.0;
    |       ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing that to be a mutable reference
+   |
+LL |   fn example(&self, input: &mut i32); // should suggest here
+   |                            ~~~~~~~~
 
 error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
   --> $DIR/issue-68049-2.rs:17:5
    |
-LL |   fn example(&self, input: &i32); // should suggest here
-   |              ----- help: consider changing that to be a mutable reference: `&mut self`
-...
 LL |     self.0 += *input;
    |     ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing that to be a mutable reference
+   |
+LL |   fn example(&mut self, input: &i32); // should suggest here
+   |              ~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
index 260df85653b156890153e712d62d14032886c4be..a2b5597847846f662621d12157fbf293e491a1e9 100644 (file)
@@ -4,10 +4,7 @@ error[E0618]: expected function, found enum variant `Alias::Unit`
 LL |        Unit,
    |        ---- enum variant `Alias::Unit` defined here
 ...
-LL |        Alias::
-   |  ______^
-   | | _____|
-   | ||
+LL | //     Alias::
 LL | ||     Unit();
    | ||________^_- call expression requires function
    |  |________|
diff --git a/src/test/ui/suggestions/method-access-to-range-literal-typo.rs b/src/test/ui/suggestions/method-access-to-range-literal-typo.rs
new file mode 100644 (file)
index 0000000..ac662ed
--- /dev/null
@@ -0,0 +1,30 @@
+fn as_ref() -> Option<Vec<u8>> {
+    None
+}
+struct Type {
+    option: Option<Vec<u8>>
+}
+trait Trait {
+    fn foo(&self) -> Vec<u8>;
+}
+impl Trait for Option<Vec<u8>> {
+    fn foo(&self) -> Vec<u8> {
+        vec![1, 2, 3]
+    }
+}
+
+impl Type {
+    fn method(&self) -> Option<Vec<u8>> {
+        self.option..as_ref().map(|x| x)
+        //~^ ERROR E0308
+    }
+    fn method2(&self) -> &u8 {
+        self.option..foo().get(0)
+        //~^ ERROR E0425
+        //~| ERROR E0308
+    }
+}
+
+fn main() {
+    let _ = Type { option: None }.method();
+}
diff --git a/src/test/ui/suggestions/method-access-to-range-literal-typo.stderr b/src/test/ui/suggestions/method-access-to-range-literal-typo.stderr
new file mode 100644 (file)
index 0000000..c84f946
--- /dev/null
@@ -0,0 +1,48 @@
+error[E0425]: cannot find function `foo` in this scope
+  --> $DIR/method-access-to-range-literal-typo.rs:22:22
+   |
+LL |         self.option..foo().get(0)
+   |                      ^^^ not found in this scope
+   |
+help: you might have meant to write `.` instead of `..`
+   |
+LL -         self.option..foo().get(0)
+LL +         self.option.foo().get(0)
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/method-access-to-range-literal-typo.rs:18:9
+   |
+LL |     fn method(&self) -> Option<Vec<u8>> {
+   |                         --------------- expected `Option<Vec<u8>>` because of return type
+LL |         self.option..as_ref().map(|x| x)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found struct `Range`
+   |
+   = note: expected enum `Option<_>`
+            found struct `std::ops::Range<Option<_>>`
+help: you likely meant to write a method call instead of a range
+   |
+LL -         self.option..as_ref().map(|x| x)
+LL +         self.option.as_ref().map(|x| x)
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/method-access-to-range-literal-typo.rs:22:9
+   |
+LL |     fn method2(&self) -> &u8 {
+   |                          --- expected `&u8` because of return type
+LL |         self.option..foo().get(0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&u8`, found struct `Range`
+   |
+   = note: expected reference `&u8`
+                 found struct `std::ops::Range<Option<Vec<u8>>>`
+help: you likely meant to write a method call instead of a range
+   |
+LL -         self.option..foo().get(0)
+LL +         self.option.foo().get(0)
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.
index cc4120041b9865e7215259af4ec5ef3a50793dc2..be4394031047f897673211556edbb8f4f8b48b17 100644 (file)
@@ -3,6 +3,6 @@
 fn two_type_params<A, B>(_: B) {}
 
 fn main() {
-    two_type_params::<String, _>(100); //~ ERROR this function takes 2 generic arguments
+    two_type_params::<String, _>(100); //~ ERROR function takes 2 generic arguments
     two_type_params::<String, _>(100);
 }
index 19286331b60232d7c21cdf485310beab74d9eda1..d444998d35bf9959f9df5e6457d9ce042034abf9 100644 (file)
@@ -3,6 +3,6 @@
 fn two_type_params<A, B>(_: B) {}
 
 fn main() {
-    two_type_params::<String>(100); //~ ERROR this function takes 2 generic arguments
+    two_type_params::<String>(100); //~ ERROR function takes 2 generic arguments
     two_type_params::<String, _>(100);
 }
index 3e0271d02572b98354603945119ef6803b174d64..474a72093c631eee83a3b62f36fdeedd09b62b02 100644 (file)
@@ -9,6 +9,10 @@ LL |                 if selection.1.unwrap().contains(selection.0) {
    |
 note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
   --> $SRC_DIR/core/src/option.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |                 if selection.1.clone().unwrap().contains(selection.0) {
+   |                                ++++++++
 
 error[E0507]: cannot move out of `selection.1` which is behind a shared reference
   --> $DIR/option-content-move.rs:27:20
@@ -21,6 +25,10 @@ LL |                 if selection.1.unwrap().contains(selection.0) {
    |
 note: `Result::<T, E>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
   --> $SRC_DIR/core/src/result.rs:LL:COL
+help: you can `clone` the value and consume it, but this might not be your desired behavior
+   |
+LL |                 if selection.1.clone().unwrap().contains(selection.0) {
+   |                                ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/shadowed-lplace-method-2.rs b/src/test/ui/suggestions/shadowed-lplace-method-2.rs
new file mode 100644 (file)
index 0000000..dab99fb
--- /dev/null
@@ -0,0 +1,23 @@
+#![allow(unused)]
+
+struct X {
+    x: (),
+}
+pub trait A {
+    fn foo(&mut self, _: usize) -> &mut ();
+}
+impl A for X {
+    fn foo(&mut self, _: usize) -> &mut () {
+        &mut self.x
+    }
+}
+impl X {
+    fn foo(&mut self, _: usize) -> &mut Self {
+        self
+    }
+}
+
+fn main() {
+    let mut x = X { x: () };
+    *x.foo(0) = (); //~ ERROR E0308
+}
diff --git a/src/test/ui/suggestions/shadowed-lplace-method-2.stderr b/src/test/ui/suggestions/shadowed-lplace-method-2.stderr
new file mode 100644 (file)
index 0000000..94eef15
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/shadowed-lplace-method-2.rs:22:17
+   |
+LL |     *x.foo(0) = ();
+   |     ---------   ^^ expected struct `X`, found `()`
+   |     |
+   |     expected due to the type of this binding
+   |
+note: the `foo` call is resolved to the method in `X`, shadowing the method of the same name on trait `A`
+  --> $DIR/shadowed-lplace-method-2.rs:22:8
+   |
+LL |     *x.foo(0) = ();
+   |        ^^^ refers to `X::foo`
+help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly
+   |
+LL |     *<_ as A>::foo(&mut x, 0) = ();
+   |      ++++++++++++++++++  ~
+help: try wrapping the expression in `X`
+   |
+LL |     *x.foo(0) = X { x: () };
+   |                 ++++++    +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/shadowed-lplace-method.fixed b/src/test/ui/suggestions/shadowed-lplace-method.fixed
new file mode 100644 (file)
index 0000000..740ac77
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+#![allow(unused_imports)]
+use std::borrow::BorrowMut;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+fn main() {
+    let rc = Rc::new(RefCell::new(true));
+    *std::cell::RefCell::<_>::borrow_mut(&rc) = false; //~ ERROR E0308
+}
diff --git a/src/test/ui/suggestions/shadowed-lplace-method.rs b/src/test/ui/suggestions/shadowed-lplace-method.rs
new file mode 100644 (file)
index 0000000..6bf1287
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+#![allow(unused_imports)]
+use std::borrow::BorrowMut;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+fn main() {
+    let rc = Rc::new(RefCell::new(true));
+    *rc.borrow_mut() = false; //~ ERROR E0308
+}
diff --git a/src/test/ui/suggestions/shadowed-lplace-method.stderr b/src/test/ui/suggestions/shadowed-lplace-method.stderr
new file mode 100644 (file)
index 0000000..91d0d12
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0308]: mismatched types
+  --> $DIR/shadowed-lplace-method.rs:9:24
+   |
+LL |     *rc.borrow_mut() = false;
+   |     ----------------   ^^^^^ expected struct `Rc`, found `bool`
+   |     |
+   |     expected due to the type of this binding
+   |
+   = note: expected struct `Rc<RefCell<bool>>`
+                found type `bool`
+note: the `borrow_mut` call is resolved to the method in `std::borrow::BorrowMut`, shadowing the method of the same name on the inherent impl for `std::cell::RefCell<T>`
+  --> $DIR/shadowed-lplace-method.rs:9:9
+   |
+LL | use std::borrow::BorrowMut;
+   |     ---------------------- `std::borrow::BorrowMut` imported here
+...
+LL |     *rc.borrow_mut() = false;
+   |         ^^^^^^^^^^ refers to `std::borrow::BorrowMut::borrow_mut`
+help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly
+   |
+LL |     *std::cell::RefCell::<_>::borrow_mut(&rc) = false;
+   |      +++++++++++++++++++++++++++++++++++++  ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index da4db46aad3d67d36178d0fd831f56afc1f12cec..5f59d0f541c99433e116610108335abbe02e9a0c 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
    |                --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found closure
    |                |
-   |                arguments to this function are incorrect
+   |                arguments to this method are incorrect
    |
    = note: expected reference `&str`
                 found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
index 9fd2658ec702db71609de9cba8ea44458c58bc86..7973759bf5ec7f188259867284dd4c673cadef1a 100644 (file)
@@ -1,37 +1,46 @@
 error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
   --> $DIR/suggest-ref-mut.rs:7:9
    |
-LL |     fn zap(&self) {
-   |            ----- help: consider changing this to be a mutable reference: `&mut self`
-...
 LL |         self.0 = 32;
    |         ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn zap(&mut self) {
+   |            ~~~~~~~~~
 
 error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
   --> $DIR/suggest-ref-mut.rs:16:5
    |
-LL |     let ref foo = 16;
-   |         ------- help: consider changing this to be a mutable reference: `ref mut foo`
-...
 LL |     *foo = 32;
    |     ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let ref mut foo = 16;
+   |         ~~~~~~~~~~~
 
 error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
   --> $DIR/suggest-ref-mut.rs:21:9
    |
-LL |     if let Some(ref bar) = Some(16) {
-   |                 ------- help: consider changing this to be a mutable reference: `ref mut bar`
-...
 LL |         *bar = 32;
    |         ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     if let Some(ref mut bar) = Some(16) {
+   |                 ~~~~~~~~~~~
 
 error[E0594]: cannot assign to `*quo`, which is behind a `&` reference
   --> $DIR/suggest-ref-mut.rs:25:22
    |
 LL |         ref quo => { *quo = 32; },
-   |         -------      ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written
-   |         |
-   |         help: consider changing this to be a mutable reference: `ref mut quo`
+   |                      ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |         ref mut quo => { *quo = 32; },
+   |         ~~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
index 7583c875a1a37a667d483998e6d7242d5d142a6e..f520d88c6ba3b0cd838ba6596966e1afa71db7fb 100644 (file)
@@ -78,7 +78,7 @@ error[E0308]: mismatched types
 LL |     x.funk(3);
    |       ---- ^ expected associated type, found integer
    |       |
-   |       arguments to this function are incorrect
+   |       arguments to this method are incorrect
    |
    = note: expected associated type `<T as Trait<i32>>::A`
                          found type `{integer}`
index ede3ebfa739c4f3ce3ca5e584799f62652aac022..24bedb5297b1fe9241d4992471c5e2773d859a02 100644 (file)
@@ -19,7 +19,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
 LL | const C: _ = || 42;
    |          ^ not allowed in type signatures
    |
-note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:16]` cannot be named
+note: however, the inferred type `[closure@unnamable-types.rs:17:14]` cannot be named
   --> $DIR/unnamable-types.rs:17:14
    |
 LL | const C: _ = || 42;
@@ -31,7 +31,7 @@ error: missing type for `const` item
 LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
    |        ^
    |
-note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
+note: however, the inferred type `S<[closure@unnamable-types.rs:23:31]>` cannot be named
   --> $DIR/unnamable-types.rs:23:11
    |
 LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
index 107af76413d3916b2dc69535b62eb39424c288c4..5b54880a685524c6cf60a08c293b3753688587a4 100644 (file)
@@ -12,7 +12,7 @@ LL | enum Quux<T> { Bar }
 help: add missing generic argument
    |
 LL | fn foo(c: Quux<T>) { assert!((false)); }
-   |           ~~~~~~~
+   |               +++
 
 error: aborting due to previous error
 
index 7fb90581f8a8fdf43115d1a0b92683e853f24af2..4b6915f77152678f063ffca2141578bf963acfa8 100644 (file)
@@ -32,12 +32,7 @@ Thir {
             kind: Scope {
                 region_scope: Node(2),
                 lint_level: Explicit(
-                    HirId {
-                        owner: OwnerId {
-                            def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
-                        },
-                        local_id: 2,
-                    },
+                    HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
                 ),
                 value: e0,
             },
index 683b1c1aa43e64abe59f8ea257bb7303b780a277..62580755c814e992ae59533bc5452eb35067e932 100644 (file)
@@ -6,8 +6,8 @@ impl Mumbo for usize {
     // Cannot have a larger effect than the trait:
     unsafe fn jumbo(&self, x: &usize) { *self + *x; }
     //~^ ERROR method `jumbo` has an incompatible type for trait
-    //~| expected fn pointer `fn
-    //~| found fn pointer `unsafe fn
+    //~| expected signature `fn
+    //~| found signature `unsafe fn
 }
 
 fn main() {}
index 30aa97d2934ddcecc21f1de30bfca84d3ce8eb88..252b5aff96a016e770b1dd08619a9bec7c17c521 100644 (file)
@@ -9,8 +9,8 @@ note: type in trait
    |
 LL |     fn jumbo(&self, x: &usize) -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected fn pointer `fn(&usize, &usize) -> usize`
-              found fn pointer `unsafe fn(&usize, &usize)`
+   = note: expected signature `fn(&usize, &usize) -> usize`
+              found signature `unsafe fn(&usize, &usize)`
 
 error: aborting due to previous error
 
index 0780109b8432ec5b653fb412705121efa3b762a1..6d985bdeaf8599018e2a30f97e4ce245cafc3403 100644 (file)
@@ -12,8 +12,8 @@ note: type in trait
    |
 LL |     fn foo(_: fn(u8) -> ());
    |               ^^^^^^^^^^^^
-   = note: expected fn pointer `fn(fn(u8))`
-              found fn pointer `fn(fn(u16))`
+   = note: expected signature `fn(fn(u8))`
+              found signature `fn(fn(u16))`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/issue-35869.rs:13:15
@@ -29,8 +29,8 @@ note: type in trait
    |
 LL |     fn bar(_: Option<u8>);
    |               ^^^^^^^^^^
-   = note: expected fn pointer `fn(Option<u8>)`
-              found fn pointer `fn(Option<u16>)`
+   = note: expected signature `fn(Option<u8>)`
+              found signature `fn(Option<u16>)`
 
 error[E0053]: method `baz` has an incompatible type for trait
   --> $DIR/issue-35869.rs:15:15
@@ -46,8 +46,8 @@ note: type in trait
    |
 LL |     fn baz(_: (u8, u16));
    |               ^^^^^^^^^
-   = note: expected fn pointer `fn((u8, _))`
-              found fn pointer `fn((u16, _))`
+   = note: expected signature `fn((u8, _))`
+              found signature `fn((u16, _))`
 
 error[E0053]: method `qux` has an incompatible type for trait
   --> $DIR/issue-35869.rs:17:17
@@ -63,8 +63,8 @@ note: type in trait
    |
 LL |     fn qux() -> u8;
    |                 ^^
-   = note: expected fn pointer `fn() -> u8`
-              found fn pointer `fn() -> u16`
+   = note: expected signature `fn() -> u8`
+              found signature `fn() -> u16`
 
 error: aborting due to 4 previous errors
 
index 0ee44921bf5f8c82a5621e813813bda2b7619b8d..7924d3db06f36efb7ce39b5e0740200fc312099e 100644 (file)
@@ -7,7 +7,7 @@ LL | impl<F, Name, P> AddClass<Name, F> for Class<P>
 LL |         builder.push(output);
    |                 ---- ^^^^^^ expected type parameter `F`, found struct `Class`
    |                 |
-   |                 arguments to this function are incorrect
+   |                 arguments to this method are incorrect
    |
    = note: expected type parameter `F`
                       found struct `Class<P>`
index 5fcd090a8349fe181c5e4e252c83f8a479bee39b..9f9acf851135f4d0a3282cede8249af04ad6f6fa 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied
-  --> $DIR/issue-91594.rs:10:1
+  --> $DIR/issue-91594.rs:10:6
    |
 LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
    |
    = help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo`
 note: required for `Foo` to implement `Component<Foo>`
diff --git a/src/test/ui/traits/issue-99875.rs b/src/test/ui/traits/issue-99875.rs
new file mode 100644 (file)
index 0000000..cf73fd8
--- /dev/null
@@ -0,0 +1,16 @@
+struct Argument;
+struct Return;
+
+fn function(_: Argument) -> Return { todo!() }
+
+trait Trait {}
+impl Trait for fn(Argument) -> Return {}
+
+fn takes(_: impl Trait) {}
+
+fn main() {
+    takes(function);
+    //~^ ERROR the trait bound
+    takes(|_: Argument| -> Return { todo!() });
+    //~^ ERROR the trait bound
+}
diff --git a/src/test/ui/traits/issue-99875.stderr b/src/test/ui/traits/issue-99875.stderr
new file mode 100644 (file)
index 0000000..3ff8f12
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
+  --> $DIR/issue-99875.rs:12:11
+   |
+LL |     takes(function);
+   |     ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
+note: required by a bound in `takes`
+  --> $DIR/issue-99875.rs:9:18
+   |
+LL | fn takes(_: impl Trait) {}
+   |                  ^^^^^ required by this bound in `takes`
+
+error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
+  --> $DIR/issue-99875.rs:14:11
+   |
+LL |     takes(|_: Argument| -> Return { todo!() });
+   |     ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `[closure@$DIR/issue-99875.rs:14:11: 14:34]`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
+note: required by a bound in `takes`
+  --> $DIR/issue-99875.rs:9:18
+   |
+LL | fn takes(_: impl Trait) {}
+   |                  ^^^^^ required by this bound in `takes`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index de1c878a51311cbc0c865bc707a932cba48d2f76..f8119ed415d036ae57f695d027594433cc0b1d91 100644 (file)
@@ -4,8 +4,8 @@ error[E0308]: method not compatible with trait
 LL |     fn foo(x: Foo<'b,'a>) {
    |     ^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected fn pointer `fn(Foo<'a, 'b>)`
-              found fn pointer `fn(Foo<'b, 'a>)`
+   = note: expected signature `fn(Foo<'a, 'b>)`
+              found signature `fn(Foo<'b, 'a>)`
 note: the lifetime `'b` as defined here...
   --> $DIR/matching-lifetimes.rs:13:9
    |
@@ -23,8 +23,8 @@ error[E0308]: method not compatible with trait
 LL |     fn foo(x: Foo<'b,'a>) {
    |     ^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected fn pointer `fn(Foo<'a, 'b>)`
-              found fn pointer `fn(Foo<'b, 'a>)`
+   = note: expected signature `fn(Foo<'a, 'b>)`
+              found signature `fn(Foo<'b, 'a>)`
 note: the lifetime `'a` as defined here...
   --> $DIR/matching-lifetimes.rs:13:6
    |
index 41fc3600fcd54e295148bce95c0602fa20068f81..30cc76b2e1aad1b450a40881f244c38211bb230b 100644 (file)
@@ -50,7 +50,7 @@ LL |     is_send((8, TestType));
    |     required by a bound introduced by this call
    |
    = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
-   = note: required because it appears within the type `({integer}, dummy1c::TestType)`
+   = note: required because it appears within the type `({integer}, TestType)`
 note: required by a bound in `is_send`
   --> $DIR/negated-auto-traits-error.rs:16:15
    |
@@ -67,7 +67,7 @@ LL |     is_send(Box::new(TestType));
    |
    = note: the trait bound `Unique<dummy2::TestType>: Send` is not satisfied
    = note: required for `Unique<dummy2::TestType>` to implement `Send`
-   = note: required because it appears within the type `Box<dummy2::TestType>`
+   = note: required because it appears within the type `Box<TestType>`
 note: required by a bound in `is_send`
   --> $DIR/negated-auto-traits-error.rs:16:15
    |
@@ -87,13 +87,13 @@ LL |     is_send(Box::new(Outer2(TestType)));
    |     required by a bound introduced by this call
    |
    = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`
-note: required because it appears within the type `Outer2<dummy3::TestType>`
+note: required because it appears within the type `Outer2<TestType>`
   --> $DIR/negated-auto-traits-error.rs:12:8
    |
 LL | struct Outer2<T>(T);
    |        ^^^^^^
    = note: required for `Unique<Outer2<dummy3::TestType>>` to implement `Send`
-   = note: required because it appears within the type `Box<Outer2<dummy3::TestType>>`
+   = note: required because it appears within the type `Box<Outer2<TestType>>`
 note: required by a bound in `is_send`
   --> $DIR/negated-auto-traits-error.rs:16:15
    |
index 118b2cf3ecd857a2a3f6d5a43c5cc182927345a6..b128b6518ce4b75d453a6462f53c48c02bb7addc 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn get_relation(&self) -> To;
 LL |     fn get_relation(&self) -> &ProofReader {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Article) -> &'1 ProofReader`
    |
-   = note: expected `fn(&'1 Article) -> &'2 ProofReader`
-              found `fn(&'1 Article) -> &'1 ProofReader`
+   = note: expected signature `fn(&'1 Article) -> &'2 ProofReader`
+              found signature `fn(&'1 Article) -> &'1 ProofReader`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/param-without-lifetime-constraint.rs:10:31
    |
index 0b1fb30478ff682667923f9791e7276a949f1e31..0ca565787f6b6a5fb8a777c0e852b8ef4fe04ba9 100644 (file)
@@ -1,12 +1,8 @@
 error[E0200]: the trait `Foo` requires an `unsafe impl` declaration
   --> $DIR/safety-trait-impl-cc.rs:9:1
    |
-LL | / impl lib::Foo for Bar {
-LL | |     fn foo(&self) -> isize {
-LL | |         panic!();
-LL | |     }
-LL | | }
-   | |_^
+LL | impl lib::Foo for Bar {
+   | ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the trait `Foo` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
 help: add `unsafe` to this trait implementation
index 721e2b48b954fa3db2194291f8a1b43069260434..e78e0e3a6baa48a9f1449763ad50952368913365 100644 (file)
@@ -2,7 +2,7 @@ error[E0200]: the trait `UnsafeTrait` requires an `unsafe impl` declaration
   --> $DIR/safety-trait-impl.rs:14:1
    |
 LL | impl UnsafeTrait for u16 { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the trait `UnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
 help: add `unsafe` to this trait implementation
@@ -14,7 +14,7 @@ error[E0199]: implementing the trait `SafeTrait` is not unsafe
   --> $DIR/safety-trait-impl.rs:16:1
    |
 LL | unsafe impl SafeTrait for u32 { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `unsafe` from this trait implementation
    |
index 85fada3b87c38a6cb8a50d18d6659f97c32d12ed..05a49820a822df0e880f3e5d9a1b2ca3e28471f1 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
 LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
    |
-   = note: expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
-              found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
+   = note: expected signature `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
+              found signature `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/self-without-lifetime-constraint.rs:41:60
    |
index aac119afda544e3b7d7bccb7a57419b92292ee4f..39b60c3119727116463b0e356b6bc2f0b8e78414 100644 (file)
@@ -1,18 +1,24 @@
 error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference
   --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:6:5
    |
-LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
-   |                        --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32`
 LL |     *t
    |     ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn reborrow_mut<'a>(t: &'a mut &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+   |                        ~~~~~~~~~~~~~~~~~~~
 
 error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference
   --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:10:6
    |
-LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
-   |                             --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32`
 LL |     {*t}
    |      ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL | fn copy_reborrow_mut<'a>(t: &'a mut &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+   |                             ~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
index 089c703fda5c7a8101544a7b9148f78b447ba4fe..01b13b29fb4ccb3f6cc3b3549b6e5cec2b619e11 100644 (file)
@@ -4,7 +4,7 @@ fn bar(s: &str, a: (&str,), s2: &str) {}
 
 fn main() {
     foo("hi", 1, 2, "hi");
-    //~^ ERROR this function takes 3 arguments but 4 arguments were supplied
+    //~^ ERROR function takes 3 arguments but 4 arguments were supplied
     bar("hi", "hi", "hi");
     //~^ ERROR mismatched types
 }
index 7029d298d71e276b670de443d15171106e47ceab..2e20a4cca0845dff2b8ef166c3b77856456bbd0e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 3 arguments but 4 arguments were supplied
+error[E0061]: function takes 3 arguments but 4 arguments were supplied
   --> $DIR/add-tuple-within-arguments.rs:6:5
    |
 LL |     foo("hi", 1, 2, "hi");
index b0f814616f2ecc492f9114042f59380140eb2d87..e1c1d748fec0a601051cde1c2fd7322e128b0ee4 100644 (file)
@@ -11,7 +11,7 @@ fn qux(&self) -> i32 {
 fn bar() {
     let x = Foo;
     test(x.qux(), x.qux());
-    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~^ ERROR function takes 1 argument but 2 arguments were supplied
 }
 
 fn main() {}
index 0c2a4c41461fc4d108f5656c5bb8917e899df08a..41244209214e7e2006e69db4ed4cb29c2ae2ea3b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: function takes 1 argument but 2 arguments were supplied
   --> $DIR/wrong_argument_ice-2.rs:13:5
    |
 LL |     test(x.qux(), x.qux());
index 951687c37596ac77578f1aa5c24eb21a91b51d3c..96633180b57eb320480999f955a22cf5b061d4a5 100644 (file)
@@ -7,7 +7,7 @@ fn test(process: &Process, groups: Vec<Group>) -> Vec<Group> {
 
     if groups.capacity() == 0 {
         groups.push(new_group, vec![process]);
-        //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+        //~^ ERROR this method takes 1 argument but 2 arguments were supplied
         return groups;
     }
 
index fe3712ef83917f1fb60cd082ca601f550bd7c86d..0a503e1fe58c1a503c2e81fb136d0e70368dd24d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: this method takes 1 argument but 2 arguments were supplied
   --> $DIR/wrong_argument_ice-3.rs:9:16
    |
 LL |         groups.push(new_group, vec![process]);
index 479bd0d819fdb921b4a59fdb1e1cc737d544afca..883d92dcce1437a26eaa95028a69e725f0419c48 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {
     (|| {})(|| {
-        //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+        //~^ ERROR function takes 0 arguments but 1 argument was supplied
         let b = 1;
     });
 }
index da967d8c1467610c87b497a2367eb7beca3bf478..b7e0225feb76dad8ee8ba0a3d52f2b85f867d5a3 100644 (file)
@@ -9,7 +9,7 @@ pub struct BuildPlanBuilder {
 impl BuildPlanBuilder {
     pub fn or(&mut self) -> &mut Self {
         self.acc.push_back(self.current_provides, self.current_requires);
-        //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+        //~^ ERROR method takes 1 argument but 2 arguments were supplied
         self
     }
 }
index 452413fc51679bd93f90cba315007b01f3b72367..f1b00ae0b9242265bcb8a3e6a87742e04a2b9752 100644 (file)
@@ -1,4 +1,4 @@
-error[E0061]: this function takes 1 argument but 2 arguments were supplied
+error[E0061]: method takes 1 argument but 2 arguments were supplied
   --> $DIR/wrong_argument_ice.rs:11:18
    |
 LL |         self.acc.push_back(self.current_provides, self.current_requires);
diff --git a/src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs b/src/test/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs
new file mode 100644 (file)
index 0000000..9626065
--- /dev/null
@@ -0,0 +1,20 @@
+//check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait Trait {
+    type Opaque1;
+    type Opaque2;
+    fn constrain(self);
+}
+
+impl<'a> Trait for &'a () {
+    type Opaque1 = impl Sized;
+    type Opaque2 = impl Sized + 'a;
+    fn constrain(self) {
+        let _: Self::Opaque1 = ();
+        let _: Self::Opaque2 = self;
+    }
+}
+
+fn main() {}
index fd43e1114c8912769e8b06fbad8aae279f66cd88..fafff19f8f6ec0cdd29a3b92a7bc25b31192ec6e 100644 (file)
@@ -28,7 +28,7 @@ LL |         input_cells: Vec::new()
 help: add missing generic argument
    |
 LL |         input_cells: Vec<T>::new()
-   |                      ~~~~~~
+   |                         +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/type/binding-assigned-block-without-tail-expression.rs b/src/test/ui/type/binding-assigned-block-without-tail-expression.rs
new file mode 100644 (file)
index 0000000..09afd27
--- /dev/null
@@ -0,0 +1,22 @@
+struct S;
+fn main() {
+    let x = {
+        println!("foo");
+        42;
+    };
+    let y = {};
+    let z = {
+        "hi";
+    };
+    let s = {
+        S;
+    };
+    println!("{}", x); //~ ERROR E0277
+    println!("{}", y); //~ ERROR E0277
+    println!("{}", z); //~ ERROR E0277
+    println!("{}", s); //~ ERROR E0277
+    let _: i32 = x; //~ ERROR E0308
+    let _: i32 = y; //~ ERROR E0308
+    let _: i32 = z; //~ ERROR E0308
+    let _: i32 = s; //~ ERROR E0308
+}
diff --git a/src/test/ui/type/binding-assigned-block-without-tail-expression.stderr b/src/test/ui/type/binding-assigned-block-without-tail-expression.stderr
new file mode 100644 (file)
index 0000000..3e96d7f
--- /dev/null
@@ -0,0 +1,109 @@
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:14:20
+   |
+LL |         42;
+   |           - help: remove this semicolon
+...
+LL |     println!("{}", x);
+   |                    ^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:15:20
+   |
+LL |     let y = {};
+   |             -- this empty block is missing a tail expression
+...
+LL |     println!("{}", y);
+   |                    ^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:16:20
+   |
+LL |         "hi";
+   |             - help: remove this semicolon
+...
+LL |     println!("{}", z);
+   |                    ^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:17:20
+   |
+LL |       let s = {
+   |  _____________-
+LL | |         S;
+LL | |     };
+   | |_____- this block is missing a tail expression
+...
+LL |       println!("{}", s);
+   |                      ^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:18:18
+   |
+LL |         42;
+   |           - help: remove this semicolon
+...
+LL |     let _: i32 = x;
+   |            ---   ^ expected `i32`, found `()`
+   |            |
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:19:18
+   |
+LL |     let y = {};
+   |             -- this empty block is missing a tail expression
+...
+LL |     let _: i32 = y;
+   |            ---   ^ expected `i32`, found `()`
+   |            |
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:20:18
+   |
+LL |       let z = {
+   |  _____________-
+LL | |         "hi";
+LL | |     };
+   | |_____- this block is missing a tail expression
+...
+LL |       let _: i32 = z;
+   |              ---   ^ expected `i32`, found `()`
+   |              |
+   |              expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/binding-assigned-block-without-tail-expression.rs:21:18
+   |
+LL |       let s = {
+   |  _____________-
+LL | |         S;
+LL | |     };
+   | |_____- this block is missing a tail expression
+...
+LL |       let _: i32 = s;
+   |              ---   ^ expected `i32`, found `()`
+   |              |
+   |              expected due to this
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type/closure-with-wrong-borrows.rs b/src/test/ui/type/closure-with-wrong-borrows.rs
new file mode 100644 (file)
index 0000000..5f6a783
--- /dev/null
@@ -0,0 +1,10 @@
+struct S<'a>(&'a str);
+
+fn f(inner: fn(&str, &S)) {
+}
+
+#[allow(unreachable_code)]
+fn main() {
+    let inner: fn(_, _) = unimplemented!();
+    f(inner); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/type/closure-with-wrong-borrows.stderr b/src/test/ui/type/closure-with-wrong-borrows.stderr
new file mode 100644 (file)
index 0000000..7370bc7
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-with-wrong-borrows.rs:9:7
+   |
+LL |     f(inner);
+   |     - ^^^^^ one type is more general than the other
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected fn pointer `for<'a, 'b, 'c> fn(&'a str, &'b S<'c>)`
+              found fn pointer `fn(_, _)`
+note: function defined here
+  --> $DIR/closure-with-wrong-borrows.rs:3:4
+   |
+LL | fn f(inner: fn(&str, &S)) {
+   |    ^ -------------------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type/issue-102598.rs b/src/test/ui/type/issue-102598.rs
new file mode 100644 (file)
index 0000000..93808f1
--- /dev/null
@@ -0,0 +1,8 @@
+fn foo<'a>(_: impl 'a Sized) {}
+//~^ ERROR: expected `+` between lifetime and Sized
+//~| ERROR: expected one of `:`, `@`, or `|`, found `)`
+//~| ERROR: expected one of `)`, `+`, or `,`, found `Sized`
+//~| ERROR: at least one trait must be specified
+
+fn main(){
+}
diff --git a/src/test/ui/type/issue-102598.stderr b/src/test/ui/type/issue-102598.stderr
new file mode 100644 (file)
index 0000000..a232395
--- /dev/null
@@ -0,0 +1,43 @@
+error: expected `+` between lifetime and Sized
+  --> $DIR/issue-102598.rs:1:20
+   |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+   |                    ^^
+   |
+help: add `+`
+   |
+LL | fn foo<'a>(_: impl 'a + Sized) {}
+   |                       +
+
+error: expected one of `:`, `@`, or `|`, found `)`
+  --> $DIR/issue-102598.rs:1:28
+   |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+   |                            ^ expected one of `:`, `@`, or `|`
+   |
+   = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this is a parameter name, give it a type
+   |
+LL | fn foo<'a>(_: impl 'a Sized: TypeName) {}
+   |                            ++++++++++
+help: if this is a type, explicitly ignore the parameter name
+   |
+LL | fn foo<'a>(_: impl 'a _: Sized) {}
+   |                       ++
+
+error: expected one of `)`, `+`, or `,`, found `Sized`
+  --> $DIR/issue-102598.rs:1:23
+   |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+   |                      -^^^^^ expected one of `)`, `+`, or `,`
+   |                      |
+   |                      help: missing `,`
+
+error: at least one trait must be specified
+  --> $DIR/issue-102598.rs:1:15
+   |
+LL | fn foo<'a>(_: impl 'a Sized) {}
+   |               ^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/type/issue-58355.rs b/src/test/ui/type/issue-58355.rs
new file mode 100644 (file)
index 0000000..3b62fde
--- /dev/null
@@ -0,0 +1,7 @@
+#![crate_type = "lib"]
+
+pub fn foo(callback: fn() -> dyn ToString) {
+    let mut x: Option<Box<dyn Fn() -> dyn ToString>> = None;
+    x = Some(Box::new(callback));
+    //~^ ERROR: the size for values of type `dyn ToString` cannot be known at compilation time
+}
diff --git a/src/test/ui/type/issue-58355.stderr b/src/test/ui/type/issue-58355.stderr
new file mode 100644 (file)
index 0000000..6f89a7b
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0277]: the size for values of type `dyn ToString` cannot be known at compilation time
+  --> $DIR/issue-58355.rs:5:14
+   |
+LL |     x = Some(Box::new(callback));
+   |              ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString`
+   = note: required because it appears within the type `fn() -> dyn ToString`
+   = note: required for the cast from `fn() -> dyn ToString` to the object type `dyn Fn() -> (dyn ToString + 'static)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 9f9b6f06bbc24f9a781d38a9b2ec0b29d32adc4b..8978c85ed493232f4f8db6ae916a9db3adf0b525 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
     let x: Vec::with_capacity(10, 20);  //~ ERROR expected type, found `10`
-    //~^ ERROR this function takes 1 argument
+    //~^ ERROR function takes 1 argument
 }
index 9f4558adab150708696dc1aba163bd6cdbacca3d..de133e5599cf96fb8d0efce000d83a58eb5f957f 100644 (file)
@@ -67,6 +67,9 @@ LL |             x == 5
 error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:44:18
    |
+LL |     if y = (Foo { foo: x }) {
+   |                        - here the type of `x` is inferred to be `usize`
+...
 LL |     if x == x && x = x && x == x {
    |        ------    ^ expected `bool`, found `usize`
    |        |
@@ -75,6 +78,9 @@ LL |     if x == x && x = x && x == x {
 error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:44:22
    |
+LL |     if y = (Foo { foo: x }) {
+   |                        - here the type of `x` is inferred to be `usize`
+...
 LL |     if x == x && x = x && x == x {
    |                      ^ expected `bool`, found `usize`
 
@@ -92,6 +98,9 @@ LL |     if x == x && x == x && x == x {
 error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:51:28
    |
+LL |     if y = (Foo { foo: x }) {
+   |                        - here the type of `x` is inferred to be `usize`
+...
 LL |     if x == x && x == x && x = x {
    |        ----------------    ^ expected `bool`, found `usize`
    |        |
diff --git a/src/test/ui/type/type-check/point-at-inference-2.rs b/src/test/ui/type/type-check/point-at-inference-2.rs
new file mode 100644 (file)
index 0000000..6557d7f
--- /dev/null
@@ -0,0 +1,13 @@
+fn bar(_: Vec<i32>) {}
+fn baz(_: &Vec<&i32>) {}
+fn main() {
+    let v = vec![&1];
+    bar(v); //~ ERROR E0308
+    let v = vec![];
+    baz(&v);
+    baz(&v);
+    bar(v); //~ ERROR E0308
+    let v = vec![];
+    baz(&v);
+    bar(v); //~ ERROR E0308
+}
diff --git a/src/test/ui/type/type-check/point-at-inference-2.stderr b/src/test/ui/type/type-check/point-at-inference-2.stderr
new file mode 100644 (file)
index 0000000..13227c5
--- /dev/null
@@ -0,0 +1,56 @@
+error[E0308]: mismatched types
+  --> $DIR/point-at-inference-2.rs:5:9
+   |
+LL |     bar(v);
+   |     --- ^ expected `i32`, found `&{integer}`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected struct `Vec<i32>`
+              found struct `Vec<&{integer}>`
+note: function defined here
+  --> $DIR/point-at-inference-2.rs:1:4
+   |
+LL | fn bar(_: Vec<i32>) {}
+   |    ^^^ -----------
+
+error[E0308]: mismatched types
+  --> $DIR/point-at-inference-2.rs:9:9
+   |
+LL |     baz(&v);
+   |          - here the type of `v` is inferred to be `Vec<&i32>`
+LL |     baz(&v);
+LL |     bar(v);
+   |     --- ^ expected `i32`, found `&i32`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected struct `Vec<i32>`
+              found struct `Vec<&i32>`
+note: function defined here
+  --> $DIR/point-at-inference-2.rs:1:4
+   |
+LL | fn bar(_: Vec<i32>) {}
+   |    ^^^ -----------
+
+error[E0308]: mismatched types
+  --> $DIR/point-at-inference-2.rs:12:9
+   |
+LL |     baz(&v);
+   |          - here the type of `v` is inferred to be `Vec<&i32>`
+LL |     bar(v);
+   |     --- ^ expected `i32`, found `&i32`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected struct `Vec<i32>`
+              found struct `Vec<&i32>`
+note: function defined here
+  --> $DIR/point-at-inference-2.rs:1:4
+   |
+LL | fn bar(_: Vec<i32>) {}
+   |    ^^^ -----------
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type/type-check/point-at-inference-3.fixed b/src/test/ui/type/type-check/point-at-inference-3.fixed
new file mode 100644 (file)
index 0000000..1a96013
--- /dev/null
@@ -0,0 +1,12 @@
+// run-rustfix
+fn main() {
+    let mut v = Vec::new();
+    v.push(0i32);
+    //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec<i32>`
+    v.push(0);
+    v.push(1i32); //~ ERROR mismatched types
+    //~^ NOTE expected `i32`, found `u32`
+    //~| NOTE arguments to this method are incorrect
+    //~| NOTE associated function defined here
+    //~| HELP change the type of the numeric literal from `u32` to `i32`
+}
diff --git a/src/test/ui/type/type-check/point-at-inference-3.rs b/src/test/ui/type/type-check/point-at-inference-3.rs
new file mode 100644 (file)
index 0000000..92910ae
--- /dev/null
@@ -0,0 +1,12 @@
+// run-rustfix
+fn main() {
+    let mut v = Vec::new();
+    v.push(0i32);
+    //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec<i32>`
+    v.push(0);
+    v.push(1u32); //~ ERROR mismatched types
+    //~^ NOTE expected `i32`, found `u32`
+    //~| NOTE arguments to this method are incorrect
+    //~| NOTE associated function defined here
+    //~| HELP change the type of the numeric literal from `u32` to `i32`
+}
diff --git a/src/test/ui/type/type-check/point-at-inference-3.stderr b/src/test/ui/type/type-check/point-at-inference-3.stderr
new file mode 100644 (file)
index 0000000..999c314
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/point-at-inference-3.rs:7:12
+   |
+LL |     v.push(0i32);
+   |            ---- this is of type `i32`, which causes `v` to be inferred as `Vec<i32>`
+...
+LL |     v.push(1u32);
+   |       ---- ^^^^ expected `i32`, found `u32`
+   |       |
+   |       arguments to this method are incorrect
+   |
+note: associated function defined here
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     v.push(1i32);
+   |             ~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type/type-check/point-at-inference.fixed b/src/test/ui/type/type-check/point-at-inference.fixed
new file mode 100644 (file)
index 0000000..f41fbe5
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+fn bar(_: Vec<i32>) {}
+fn baz(_: &impl std::any::Any) {}
+fn main() {
+    let v = vec![1, 2, 3, 4, 5];
+    let mut foo = vec![];
+    baz(&foo);
+    for i in &v {
+        foo.push(*i);
+    }
+    baz(&foo);
+    bar(foo); //~ ERROR E0308
+}
diff --git a/src/test/ui/type/type-check/point-at-inference.rs b/src/test/ui/type/type-check/point-at-inference.rs
new file mode 100644 (file)
index 0000000..6419e42
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+fn bar(_: Vec<i32>) {}
+fn baz(_: &impl std::any::Any) {}
+fn main() {
+    let v = vec![1, 2, 3, 4, 5];
+    let mut foo = vec![];
+    baz(&foo);
+    for i in &v {
+        foo.push(i);
+    }
+    baz(&foo);
+    bar(foo); //~ ERROR E0308
+}
diff --git a/src/test/ui/type/type-check/point-at-inference.stderr b/src/test/ui/type/type-check/point-at-inference.stderr
new file mode 100644 (file)
index 0000000..70428fe
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0308]: mismatched types
+  --> $DIR/point-at-inference.rs:12:9
+   |
+LL |         foo.push(i);
+   |                  - this is of type `&{integer}`, which causes `foo` to be inferred as `Vec<&{integer}>`
+...
+LL |     bar(foo);
+   |     --- ^^^ expected `i32`, found `&{integer}`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected struct `Vec<i32>`
+              found struct `Vec<&{integer}>`
+note: function defined here
+  --> $DIR/point-at-inference.rs:2:4
+   |
+LL | fn bar(_: Vec<i32>) {}
+   |    ^^^ -----------
+help: consider dereferencing the borrow
+   |
+LL |         foo.push(*i);
+   |                  +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/typeck/issue-105946.rs b/src/test/ui/typeck/issue-105946.rs
new file mode 100644 (file)
index 0000000..bf01751
--- /dev/null
@@ -0,0 +1,12 @@
+fn digit() -> str {
+  return {};
+  //~^ ERROR: mismatched types [E0308]
+}
+fn main() {
+    let [_y..] = [box 1, box 2];
+    //~^ ERROR: cannot find value `_y` in this scope [E0425]
+    //~| ERROR: `X..` patterns in slices are experimental [E0658]
+    //~| ERROR: box expression syntax is experimental; you can call `Box::new` instead [E0658]
+    //~| ERROR: box expression syntax is experimental; you can call `Box::new` instead [E0658]
+    //~| ERROR: pattern requires 1 element but array has 2 [E0527]
+}
diff --git a/src/test/ui/typeck/issue-105946.stderr b/src/test/ui/typeck/issue-105946.stderr
new file mode 100644 (file)
index 0000000..d803de4
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0425]: cannot find value `_y` in this scope
+  --> $DIR/issue-105946.rs:6:10
+   |
+LL |     let [_y..] = [box 1, box 2];
+   |          ^^ not found in this scope
+
+error[E0658]: `X..` patterns in slices are experimental
+  --> $DIR/issue-105946.rs:6:10
+   |
+LL |     let [_y..] = [box 1, box 2];
+   |          ^^^^
+   |
+   = note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
+   = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
+
+error[E0658]: box expression syntax is experimental; you can call `Box::new` instead
+  --> $DIR/issue-105946.rs:6:19
+   |
+LL |     let [_y..] = [box 1, box 2];
+   |                   ^^^^^
+   |
+   = note: see issue #49733 <https://github.com/rust-lang/rust/issues/49733> for more information
+   = help: add `#![feature(box_syntax)]` to the crate attributes to enable
+
+error[E0658]: box expression syntax is experimental; you can call `Box::new` instead
+  --> $DIR/issue-105946.rs:6:26
+   |
+LL |     let [_y..] = [box 1, box 2];
+   |                          ^^^^^
+   |
+   = note: see issue #49733 <https://github.com/rust-lang/rust/issues/49733> for more information
+   = help: add `#![feature(box_syntax)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+  --> $DIR/issue-105946.rs:2:10
+   |
+LL |   return {};
+   |          ^^ expected `str`, found `()`
+
+error[E0527]: pattern requires 1 element but array has 2
+  --> $DIR/issue-105946.rs:6:9
+   |
+LL |     let [_y..] = [box 1, box 2];
+   |         ^^^^^^ expected 2 elements
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0527, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/typeck/issue-18937-1.rs b/src/test/ui/typeck/issue-18937-1.rs
new file mode 100644 (file)
index 0000000..57e56d8
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+// Test that we are able to type-check this example. In particular,
+// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because
+// when `T=[U]` it implies that `U: 'a`).
+//
+// Regr. test for live code we found in the wild when fixing #18937.
+
+pub trait Leak<T : ?Sized> {
+    fn leak<'a>(self) -> &'a T where T: 'a;
+}
+
+impl<U> Leak<[U]> for Vec<U> {
+    fn leak<'a>(mut self) -> &'a [U] where [U]: 'a {
+        let r: *mut [U] = &mut self[..];
+        std::mem::forget(self);
+        unsafe { &mut *r }
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/typeck/issue-18937.rs b/src/test/ui/typeck/issue-18937.rs
new file mode 100644 (file)
index 0000000..af85e5b
--- /dev/null
@@ -0,0 +1,40 @@
+// Regression test for #18937.
+
+use std::fmt;
+
+#[derive(Debug)]
+struct MyString<'a>(&'a String);
+
+struct B {
+    list: Vec<Box<dyn fmt::Debug>>,
+}
+
+trait A<'a> {
+    fn foo<F>(&mut self, f: F)
+        where F: fmt::Debug + 'a,
+              Self: Sized;
+}
+
+impl<'a> A<'a> for B {
+    fn foo<F>(&mut self, f: F)
+        where F: fmt::Debug + 'static, //~ ERROR impl has stricter
+    {
+        self.list.push(Box::new(f));
+    }
+}
+
+fn main() {
+    let mut b = B { list: Vec::new() };
+
+    // Create a borrowed pointer, put it in `b`, then drop what's borrowing it
+    let a = "hello".to_string();
+    b.foo(MyString(&a));
+
+    // Drop the data which `b` has a reference to
+    drop(a);
+
+    // Use the data, probably segfaulting
+    for b in b.list.iter() {
+        println!("{:?}", b);
+    }
+}
diff --git a/src/test/ui/typeck/issue-18937.stderr b/src/test/ui/typeck/issue-18937.stderr
new file mode 100644 (file)
index 0000000..5e2ba0e
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/issue-18937.rs:20:31
+   |
+LL | /     fn foo<F>(&mut self, f: F)
+LL | |         where F: fmt::Debug + 'a,
+LL | |               Self: Sized;
+   | |__________________________- definition of `foo` from trait
+...
+LL |           where F: fmt::Debug + 'static,
+   |                                 ^^^^^^^ impl has extra requirement `F: 'static`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0276`.
diff --git a/src/test/ui/typeck/issue-31173.rs b/src/test/ui/typeck/issue-31173.rs
new file mode 100644 (file)
index 0000000..f678df5
--- /dev/null
@@ -0,0 +1,15 @@
+use std::vec::IntoIter;
+
+pub fn get_tok(it: &mut IntoIter<u8>) {
+    let mut found_e = false;
+
+    let temp: Vec<u8> = it
+        .take_while(|&x| {
+            found_e = true;
+            false
+        })
+        .cloned() //~ ERROR to be an iterator that yields `&_`, but it yields `u8`
+        .collect(); //~ ERROR the method
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-31173.stderr b/src/test/ui/typeck/issue-31173.stderr
new file mode 100644 (file)
index 0000000..f3be99f
--- /dev/null
@@ -0,0 +1,45 @@
+error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
+  --> $DIR/issue-31173.rs:11:10
+   |
+LL |         .cloned()
+   |          ^^^^^^ expected reference, found `u8`
+   |
+   = note: expected reference `&_`
+                   found type `u8`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/issue-31173.rs:3:20
+   |
+LL |   pub fn get_tok(it: &mut IntoIter<u8>) {
+   |                      ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
+...
+LL |           .take_while(|&x| {
+   |  __________-
+LL | |             found_e = true;
+LL | |             false
+LL | |         })
+   | |__________- `Iterator::Item` remains `u8` here
+note: required by a bound in `cloned`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
+  --> $DIR/issue-31173.rs:12:10
+   |
+LL |         .collect();
+   |          ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+  --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
+   |
+   = note: doesn't satisfy `<_ as Iterator>::Item = &_`
+  --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
+   |
+   = note: doesn't satisfy `_: Iterator`
+   |
+   = note: the following trait bounds were not satisfied:
+           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
+           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0599.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/typeck/nonexistent-field-not-ambiguous.rs b/src/test/ui/typeck/nonexistent-field-not-ambiguous.rs
new file mode 100644 (file)
index 0000000..1cd192b
--- /dev/null
@@ -0,0 +1,8 @@
+struct Foo {
+    val: MissingType,
+    //~^ ERROR cannot find type `MissingType` in this scope
+}
+
+fn main() {
+    Foo { val: Default::default() };
+}
diff --git a/src/test/ui/typeck/nonexistent-field-not-ambiguous.stderr b/src/test/ui/typeck/nonexistent-field-not-ambiguous.stderr
new file mode 100644 (file)
index 0000000..76a2a5f
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `MissingType` in this scope
+  --> $DIR/nonexistent-field-not-ambiguous.rs:2:10
+   |
+LL |     val: MissingType,
+   |          ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/typeck/quiet-type-err-let-binding.rs b/src/test/ui/typeck/quiet-type-err-let-binding.rs
new file mode 100644 (file)
index 0000000..a6eab53
--- /dev/null
@@ -0,0 +1,17 @@
+// fn foo() -> String {
+//    String::new()
+// }
+
+fn test(s: &str) {
+    println!("{}", s);
+}
+
+fn test2(s: String) {
+    println!("{}", s);
+}
+
+fn main() {
+    let x = foo(); //~ERROR cannot find function `foo` in this scope
+    test(&x);
+    test2(x); // Does not complain about `x` being a `&str`.
+}
diff --git a/src/test/ui/typeck/quiet-type-err-let-binding.stderr b/src/test/ui/typeck/quiet-type-err-let-binding.stderr
new file mode 100644 (file)
index 0000000..ad7f85e
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0425]: cannot find function `foo` in this scope
+  --> $DIR/quiet-type-err-let-binding.rs:14:13
+   |
+LL |     let x = foo();
+   |             ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index a9338c76cdc8800a447d14387f7ddbb053bf54ef..d09306bf7941fd10070ecd7916bf6fb303232cb2 100644 (file)
@@ -4,6 +4,6 @@ fn l(_a: Vec<u8>) {}
 
 fn main() {
     l(vec![])
-    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~^ ERROR function takes 1 argument but 2 arguments were supplied
     //~| HELP remove the extra argument
 }
index 659cb8b267fd5b8fb80d8dad101788241120a04d..2181c37cee913a5904222a74a7baca472d2efb35 100644 (file)
@@ -4,6 +4,6 @@ fn l(_a: Vec<u8>) {}
 
 fn main() {
     l(vec![], vec![])
-    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~^ ERROR function takes 1 argument but 2 arguments were supplied
     //~| HELP remove the extra argument
 }
index 22fedb22d66c6b9b2fe96046bbd9706889062493..b96c5271339598331be6f2479780a645b9f9a32c 100644 (file)
@@ -220,3 +220,11 @@ fn value() -> Option<&'static _> {
 
 const _: Option<_> = map(value);
 //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+
+fn evens_squared(n: usize) -> _ {
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    (1..n).filter(|x| x % 2 == 0).map(|x| x * x)
+}
+
+const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
index c57f71b8057a956a93c67ea818679891ee4d9b85..bc02547c65eb8d89f4954ea75a31166f7d5de7b1 100644 (file)
@@ -428,6 +428,27 @@ LL | const _: Option<_> = map(value);
    |          not allowed in type signatures
    |          help: replace with the correct type: `Option<u8>`
 
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/typeck_type_placeholder_item.rs:224:31
+   |
+LL | fn evens_squared(n: usize) -> _ {
+   |                               ^
+   |                               |
+   |                               not allowed in type signatures
+   |                               help: replace with an appropriate return type: `impl Iterator<Item = usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/typeck_type_placeholder_item.rs:229:10
+   |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |          ^ not allowed in type signatures
+   |
+note: however, the inferred type `Map<Filter<Range<i32>, [closure@typeck_type_placeholder_item.rs:229:29]>, [closure@typeck_type_placeholder_item.rs:229:49]>` cannot be named
+  --> $DIR/typeck_type_placeholder_item.rs:229:14
+   |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:140:31
    |
@@ -636,7 +657,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error: aborting due to 69 previous errors
+error: aborting due to 71 previous errors
 
 Some errors have detailed explanations: E0121, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
index 3950dc9877cd8e3eb620946a2e935b09411b94d2..5f7f6aa9f6ec62697ef4ae895994f184dd6686de 100644 (file)
@@ -205,7 +205,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/ufcs-partially-resolved.rs:36:12
    |
 LL |     let _: <u8 as Tr>::Y::NN;
-   |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u16 as Trait>::NN`
+   |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
 
 error[E0599]: no associated item named `NN` found for type `u16` in the current scope
   --> $DIR/ufcs-partially-resolved.rs:38:20
index a832964d220a798daca3371671ed6f34288a67f5..d0ec47d61321a6642de619bd91e7671485504b39 100644 (file)
@@ -12,7 +12,7 @@ LL | pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
 help: add missing generic argument
    |
 LL |     <String as IntoCow<B>>::into_cow("foo".to_string());
-   |                ~~~~~~~~~~
+   |                       +++
 
 error[E0107]: missing generics for trait `IntoCow`
   --> $DIR/ufcs-qpath-missing-params.rs:17:16
@@ -28,7 +28,7 @@ LL | pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
 help: add missing generic argument
    |
 LL |     <String as IntoCow<B>>::into_cow::<str>("foo".to_string());
-   |                ~~~~~~~~~~
+   |                       +++
 
 error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/ufcs-qpath-missing-params.rs:17:26
index 167479270b54675954ababd7c93061556452770f..6d5dbca0558580a0e2dc934c7c112f946c83e4ed 100644 (file)
@@ -2,12 +2,17 @@ error[E0644]: closure/generator type that references itself
   --> $DIR/unboxed-closure-no-cyclic-sig.rs:8:7
    |
 LL |     g(|_| {  });
-   |       ^^^^^^^^ cyclic type of infinite size
+   |       ^^^ cyclic type of infinite size
    |
    = note: closures cannot capture themselves or take themselves as argument;
            this error may be the result of a recent compiler bug-fix,
            see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
            for more information
+note: required by a bound in `g`
+  --> $DIR/unboxed-closure-no-cyclic-sig.rs:5:24
+   |
+LL | fn g<F>(_: F) where F: FnOnce(Option<F>) {}
+   |                        ^^^^^^^^^^^^^^^^^ required by this bound in `g`
 
 error: aborting due to previous error
 
index f202492eda553ad4b5ec5eefe8aecf61914d8dfd..51fe118c93ff146c6f67d8da2cdf9437f1d21daa 100644 (file)
@@ -5,7 +5,7 @@
 fn main() {
     let _f = {
         let x = 0;
-        || x //~ ERROR `x` does not live long enough
+        || x //~ ERROR closure may outlive the current block, but it borrows `x`
     };
     _f;
 }
index b40b2f67d9bade1707c36211f30dfa55bc39c9ab..43e9af24a7c2bc0d655e0cb36b2145a6284fe741 100644 (file)
@@ -1,16 +1,21 @@
-error[E0597]: `x` does not live long enough
-  --> $DIR/unboxed-closure-region.rs:8:12
+error[E0373]: closure may outlive the current block, but it borrows `x`, which is owned by the current block
+  --> $DIR/unboxed-closure-region.rs:8:9
    |
-LL |     let _f = {
-   |         -- borrow later stored here
-LL |         let x = 0;
 LL |         || x
-   |         -- ^ borrowed value does not live long enough
+   |         ^^ - `x` is borrowed here
    |         |
-   |         value captured here
-LL |     };
-   |     - `x` dropped here while still borrowed
+   |         may outlive borrowed value `x`
+   |
+note: block requires argument type to outlive `'1`
+  --> $DIR/unboxed-closure-region.rs:6:9
+   |
+LL |     let _f = {
+   |         ^^
+help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
+   |
+LL |         move || x
+   |         ++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
index a0ed56d4bcf7bf20ff20ce696debf0734bb9d5aa..5c93ed6d7f70f471ae74f2b826bc6279745baea6 100644 (file)
@@ -12,13 +12,16 @@ LL |         tick1();
 error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5
    |
-LL |     let tick2 = || {
-   |         ----- help: consider changing this to be mutable: `mut tick2`
 LL |         tick1();
    |         ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
 ...
 LL |     tick2();
    |     ^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick2 = || {
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 27d23e3fa044bb5f261478c435f44f0971da4639..3f539c42d9b311150db5ba0f4305132cb14853c3 100644 (file)
@@ -2,11 +2,14 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
    |
 LL |     let tick = || counter += 1;
-   |         ----      ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
-   |         |
-   |         help: consider changing this to be mutable: `mut tick`
+   |                   ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
 LL |     tick();
    |     ^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick = || counter += 1;
+   |         +++
 
 error: aborting due to previous error
 
index c00f986c397a7240012490b0823521d9a8c82d3e..e3b19297b9c18d086b25f99c19d8de856bfa9986 100644 (file)
@@ -2,11 +2,14 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
    |
 LL |     let tick = move || counter += 1;
-   |         ----           ------- calling `tick` requires mutable binding due to possible mutation of `counter`
-   |         |
-   |         help: consider changing this to be mutable: `mut tick`
+   |                        ------- calling `tick` requires mutable binding due to possible mutation of `counter`
 LL |     tick();
    |     ^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick = move || counter += 1;
+   |         +++
 
 error: aborting due to previous error
 
index fe726cb49c73737a3c244d520e5ceba3dbbf7c67..f4d14b5f87bec9fd1bb52881b9e8227f1cd18017 100644 (file)
@@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
+   |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+  --> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
+   |
+LL |     T: WithType<&u32>
+   |        ^
 
 error: aborting due to previous error
 
index fe726cb49c73737a3c244d520e5ceba3dbbf7c67..f4d14b5f87bec9fd1bb52881b9e8227f1cd18017 100644 (file)
@@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
+   |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+  --> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
+   |
+LL |     T: WithType<&u32>
+   |        ^
 
 error: aborting due to previous error
 
index fbd14de21078b1440a47035103bbf782f88edc9d..63fc1a19b9383e53b686fe8ee0c2a5a1712e5792 100644 (file)
@@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
+   |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+  --> $DIR/where-clause-trait-impl-region.rs:11:8
+   |
+LL |     T: WithType<&u32>
+   |        ^
 
 error: aborting due to previous error
 
index fbd14de21078b1440a47035103bbf782f88edc9d..63fc1a19b9383e53b686fe8ee0c2a5a1712e5792 100644 (file)
@@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
    |
 LL |     T: WithType<&u32>
    |                 ^ explicit lifetime name needed here
+   |
+help: consider introducing a higher-ranked lifetime here with `for<'a>`
+  --> $DIR/where-clause-trait-impl-region.rs:11:8
+   |
+LL |     T: WithType<&u32>
+   |        ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/auxiliary/issue-106126.rs b/src/test/ui/unsafe/auxiliary/issue-106126.rs
new file mode 100644 (file)
index 0000000..091a3ed
--- /dev/null
@@ -0,0 +1,9 @@
+#[macro_export]
+macro_rules! foo {
+    () => {
+        unsafe fn __unsf() {}
+        unsafe fn __foo() {
+            __unsf();
+        }
+    };
+}
diff --git a/src/test/ui/unsafe/issue-106126-good-path-bug.rs b/src/test/ui/unsafe/issue-106126-good-path-bug.rs
new file mode 100644 (file)
index 0000000..93f478e
--- /dev/null
@@ -0,0 +1,12 @@
+// Regression test for #106126.
+// check-pass
+// aux-build:issue-106126.rs
+
+#![deny(unsafe_op_in_unsafe_fn)]
+
+#[macro_use]
+extern crate issue_106126;
+
+foo!();
+
+fn main() {}
index 03a251be1a9141572c001b7ad5ce2822e79533ee..1fc84ca02560d9184f25916eeb7d7aa0759b17ca 100644 (file)
@@ -7,8 +7,8 @@ trait Foo {
 impl Foo for u32 {
     fn len(&self) -> u32 { *self }
     //~^ ERROR method `len` has an incompatible type for trait
-    //~| expected fn pointer `unsafe fn(&u32) -> _`
-    //~| found fn pointer `fn(&u32) -> _`
+    //~| expected signature `unsafe fn(&u32) -> _`
+    //~| found signature `fn(&u32) -> _`
 }
 
 fn main() { }
index 8a0cba1fac5558c9a214992ae5a049a3781017c8..18ba79404b77e894cb4372b894bed4d7af261b62 100644 (file)
@@ -9,8 +9,8 @@ note: type in trait
    |
 LL |     unsafe fn len(&self) -> u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected fn pointer `unsafe fn(&u32) -> _`
-              found fn pointer `fn(&u32) -> _`
+   = note: expected signature `unsafe fn(&u32) -> _`
+              found signature `fn(&u32) -> _`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized-locals/suggest-borrow.rs b/src/test/ui/unsized-locals/suggest-borrow.rs
new file mode 100644 (file)
index 0000000..0869485
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let x: [u8] = vec!(1, 2, 3)[..]; //~ ERROR E0277
+    let x: &[u8] = vec!(1, 2, 3)[..]; //~ ERROR E0308
+    let x: [u8] = &vec!(1, 2, 3)[..]; //~ ERROR E0308
+    //~^ ERROR E0277
+    let x: &[u8] = &vec!(1, 2, 3)[..];
+}
diff --git a/src/test/ui/unsized-locals/suggest-borrow.stderr b/src/test/ui/unsized-locals/suggest-borrow.stderr
new file mode 100644 (file)
index 0000000..08745ea
--- /dev/null
@@ -0,0 +1,60 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/suggest-borrow.rs:2:9
+   |
+LL |     let x: [u8] = vec!(1, 2, 3)[..];
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+   |
+LL |     let x: &[u8] = vec!(1, 2, 3)[..];
+   |            +
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-borrow.rs:3:20
+   |
+LL |     let x: &[u8] = vec!(1, 2, 3)[..];
+   |            -----   ^^^^^^^^^^^^^^^^^
+   |            |       |
+   |            |       expected `&[u8]`, found slice `[{integer}]`
+   |            |       help: consider borrowing here: `&vec!(1, 2, 3)[..]`
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-borrow.rs:4:19
+   |
+LL |     let x: [u8] = &vec!(1, 2, 3)[..];
+   |            ----   ^^^^^^^^^^^^^^^^^^ expected slice `[u8]`, found `&[{integer}]`
+   |            |
+   |            expected due to this
+   |
+help: consider removing the borrow
+   |
+LL -     let x: [u8] = &vec!(1, 2, 3)[..];
+LL +     let x: [u8] = vec!(1, 2, 3)[..];
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let x: &[u8] = &vec!(1, 2, 3)[..];
+   |            +
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/suggest-borrow.rs:4:9
+   |
+LL |     let x: [u8] = &vec!(1, 2, 3)[..];
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+   |
+LL |     let x: &[u8] = &vec!(1, 2, 3)[..];
+   |            +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
index da77026673d96c51a08c8b180bd9a12df830e2fd..ace5a87187b8d1537f612cfc91e115dea1efd0ea 100644 (file)
@@ -27,6 +27,10 @@ LL |     let _foo: [u8] = *foo;
    = help: the trait `Sized` is not implemented for `[u8]`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+   |
+LL |     let _foo: &[u8] = *foo;
+   |               +
 
 error: aborting due to 3 previous errors
 
index 011f2b426c7cf140ae71f82de0bc1c41646faa76..18ac1ea18751542fdf9489871f5b10a31713cd5b 100644 (file)
@@ -14,6 +14,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
 LL + fn f1<W: ?Sized, X: ?Sized, Y, Z: ?Sized>(x: &X) {
    |
+help: consider borrowing here
+   |
+LL |     let y: &Y;
+   |            +
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:7:12
@@ -62,6 +66,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
 LL + fn f2<X, Y: ?Sized>(x: &X) {
    |
+help: consider borrowing here
+   |
+LL |     let y: &X;
+   |            +
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized6.rs:17:12
@@ -94,6 +102,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
    |
+help: consider borrowing here
+   |
+LL |     let y: &X = *x1;
+   |            +
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:24:9
@@ -144,6 +156,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL + fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
    |
+help: consider borrowing here
+   |
+LL |     let y: &X = *x1;
+   |            +
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:32:9
index 219f5bca9e3015a87e4d3b5bff5e5a107c3e8299..f9732d02cb285c57fa06dff908511071f3387a19 100644 (file)
@@ -6,3 +6,4 @@ LL | struct Foo<T: Trait> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0208`.
index 94f770eda33efbf1fef3446fd2b6ac4c3de955a6..5ce62884e1d83ee15bf557e1a6271b6c6d34a753 100644 (file)
@@ -12,3 +12,4 @@ LL | struct Bar<'a, T : Trait<'a>> {
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0208`.
index ceee53aff105db74ea25f2b3fefe5b597baefdca..1c3c1a6d1f223ce564326a353016f169af01485d 100644 (file)
@@ -6,3 +6,4 @@ LL | struct Foo<'a> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0208`.
index 25fb22732151cc90b653c2606ccca4e034827d37..27d69b6e82575d319506341a2e3b9b6204e6c980 100644 (file)
@@ -42,3 +42,4 @@ LL | enum Test8<'a, 'b, 'c:'b> {
 
 error: aborting due to 7 previous errors
 
+For more information about this error, try `rustc --explain E0208`.
index fc52492d7efddfbd632c50140c44cc51e521029f..535e97db3fb10fce823aa4a53d9182ba5e0fadbc 100644 (file)
@@ -30,3 +30,4 @@ LL | struct Derived4<'a, 'b, 'c:'b> {
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0208`.
index e3ef339f423bcdb8dd4169815d203523aa68ca9c..3f6ca62a64069776d37fb0c7e966ef9f8be3c4ab 100644 (file)
@@ -24,3 +24,4 @@ LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0208`.
index c86cf1f82b45dcc5e02964a511efe03ad5792f92..9a2c924b96a9539fc07f2dde3508b91d12f09f96 100644 (file)
@@ -6,3 +6,4 @@ LL | struct TOption<'a> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0208`.
index dbe8af75d5178d20dd1f76cce42c26d807326d3f..523763b8a07b44340cf9f47e16278a6516a74d71 100644 (file)
@@ -30,3 +30,4 @@ LL | struct TestObject<A, R> {
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0208`.
index 8358b18b73ce202ad3690a262d03f4f66ed0605e..5a5aaecffc5eb8d32ecb0b6b211cc25a66fbb1b4 100644 (file)
@@ -36,3 +36,4 @@ LL | enum Enum<A,B,C> {
 
 error: aborting due to 6 previous errors
 
+For more information about this error, try `rustc --explain E0208`.
index fcf3f15e4d3f6f98ecdbadd689a8b3682480a470..5227badb77dde78a122aaa4cc59465b3ffceb844 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA` is not satisfied
-  --> $DIR/issue-103573.rs:18:5
+  --> $DIR/issue-103573.rs:18:18
    |
 LL |     fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitA` is not implemented for `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitA` is not implemented for `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB`
    |
 help: consider further restricting the associated type
    |
index 78312a0910594105190791d871ecc48b7a1a1814..b03023b5fd14f707d69bdeb7c927305ae6a36cac 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `(): Foo` is not satisfied
-  --> $DIR/wf-foreign-fn-decl-ret.rs:11:5
+  --> $DIR/wf-foreign-fn-decl-ret.rs:11:25
    |
 LL |     pub fn lint_me() -> <() as Foo>::Assoc;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |                         ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
 
 error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
   --> $DIR/wf-foreign-fn-decl-ret.rs:14:32
index a65765c86c8b72956532f957a56087d128e5eb4f..286267c3834abc3b5e5f3fe7ea61fb23b74ba549 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/writing-to-immutable-vec.rs:3:5
    |
-LL |     let v: Vec<isize> = vec![1, 2, 3];
-   |         - help: consider changing this to be mutable: `mut v`
 LL |     v[1] = 4;
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut v: Vec<isize> = vec![1, 2, 3];
+   |         +++
 
 error: aborting due to previous error
 
index 8338f61b22a756941d048eaa59d04c33263e8b99..504a6032b01f9145c06fba675a50f1b79c21592d 100644 (file)
@@ -7,8 +7,8 @@ LL |     fn mul(self, s: &f64) -> Vec1 {
    |                     expected `f64`, found `&f64`
    |                     help: change the parameter type to match the trait: `f64`
    |
-   = note: expected fn pointer `fn(Vec1, f64) -> Vec1`
-              found fn pointer `fn(Vec1, &f64) -> Vec1`
+   = note: expected signature `fn(Vec1, f64) -> Vec1`
+              found signature `fn(Vec1, &f64) -> Vec1`
 
 error[E0053]: method `mul` has an incompatible type for trait
   --> $DIR/wrong-mul-method-signature.rs:33:21
@@ -19,8 +19,8 @@ LL |     fn mul(self, s: f64) -> Vec2 {
    |                     expected struct `Vec2`, found `f64`
    |                     help: change the parameter type to match the trait: `Vec2`
    |
-   = note: expected fn pointer `fn(Vec2, Vec2) -> f64`
-              found fn pointer `fn(Vec2, f64) -> Vec2`
+   = note: expected signature `fn(Vec2, Vec2) -> f64`
+              found signature `fn(Vec2, f64) -> Vec2`
 
 error[E0053]: method `mul` has an incompatible type for trait
   --> $DIR/wrong-mul-method-signature.rs:52:29
@@ -31,8 +31,8 @@ LL |     fn mul(self, s: f64) -> f64 {
    |                             expected `i32`, found `f64`
    |                             help: change the output type to match the trait: `i32`
    |
-   = note: expected fn pointer `fn(Vec3, _) -> i32`
-              found fn pointer `fn(Vec3, _) -> f64`
+   = note: expected signature `fn(Vec3, _) -> i32`
+              found signature `fn(Vec3, _) -> f64`
 
 error[E0308]: mismatched types
   --> $DIR/wrong-mul-method-signature.rs:63:45
diff --git a/src/test/ui/z-crate-attr.rs b/src/test/ui/z-crate-attr.rs
deleted file mode 100644 (file)
index 1021774..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// run-pass
-// This test checks if an unstable feature is enabled with the -Zcrate-attr=feature(foo) flag. If
-// the exact feature used here is causing problems feel free to replace it with another
-// perma-unstable feature.
-
-// compile-flags: -Zcrate-attr=feature(abi_unadjusted)
-
-#![allow(dead_code)]
-
-extern "unadjusted" fn foo() {}
-
-fn main() {}
index 0551e835bb0e75ec71288c34b5c894245d354f8a..21dad9eb74aa96d8679ffd7bae28250d7339923a 100644 (file)
@@ -51,7 +51,7 @@
     "aarch64-apple-darwin",
     "aarch64-apple-ios",
     "aarch64-apple-ios-sim",
-    "aarch64-fuchsia",
+    "aarch64-unknown-fuchsia",
     "aarch64-linux-android",
     "aarch64-pc-windows-msvc",
     "aarch64-unknown-hermit",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
     "x86_64-fortanix-unknown-sgx",
-    "x86_64-fuchsia",
+    "x86_64-unknown-fuchsia",
     "x86_64-linux-android",
     "x86_64-pc-windows-gnu",
     "x86_64-pc-windows-msvc",
diff --git a/src/tools/build_helper/Cargo.toml b/src/tools/build_helper/Cargo.toml
new file mode 100644 (file)
index 0000000..99f6fea
--- /dev/null
@@ -0,0 +1,8 @@
+[package]
+name = "build_helper"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs
new file mode 100644 (file)
index 0000000..9f113c7
--- /dev/null
@@ -0,0 +1,40 @@
+use std::process::Command;
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum CiEnv {
+    /// Not a CI environment.
+    None,
+    /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds.
+    AzurePipelines,
+    /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds.
+    GitHubActions,
+}
+
+impl CiEnv {
+    /// Obtains the current CI environment.
+    pub fn current() -> CiEnv {
+        if std::env::var("TF_BUILD").map_or(false, |e| e == "True") {
+            CiEnv::AzurePipelines
+        } else if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") {
+            CiEnv::GitHubActions
+        } else {
+            CiEnv::None
+        }
+    }
+
+    pub fn is_ci() -> bool {
+        Self::current() != CiEnv::None
+    }
+
+    /// If in a CI environment, forces the command to run with colors.
+    pub fn force_coloring_in_ci(self, cmd: &mut Command) {
+        if self != CiEnv::None {
+            // Due to use of stamp/docker, the output stream of rustbuild is not
+            // a TTY in CI, so coloring is by-default turned off.
+            // The explicit `TERM=xterm` environment is needed for
+            // `--color always` to actually work. This env var was lost when
+            // compiling through the Makefile. Very strange.
+            cmd.env("TERM", "xterm").args(&["--color", "always"]);
+        }
+    }
+}
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
new file mode 100644 (file)
index 0000000..dc62051
--- /dev/null
@@ -0,0 +1,75 @@
+use std::{path::Path, process::Command};
+
+/// Finds the remote for rust-lang/rust.
+/// For example for these remotes it will return `upstream`.
+/// ```text
+/// origin  https://github.com/Nilstrieb/rust.git (fetch)
+/// origin  https://github.com/Nilstrieb/rust.git (push)
+/// upstream        https://github.com/rust-lang/rust (fetch)
+/// upstream        https://github.com/rust-lang/rust (push)
+/// ```
+pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result<String, String> {
+    let mut git = Command::new("git");
+    if let Some(git_dir) = git_dir {
+        git.current_dir(git_dir);
+    }
+    git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
+
+    let output = git.output().map_err(|err| format!("{err:?}"))?;
+    if !output.status.success() {
+        return Err("failed to execute git config command".to_owned());
+    }
+
+    let stdout = String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?;
+
+    let rust_lang_remote = stdout
+        .lines()
+        .find(|remote| remote.contains("rust-lang"))
+        .ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
+
+    let remote_name =
+        rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
+    Ok(remote_name.into())
+}
+
+pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
+    let mut git = Command::new("git");
+    if let Some(git_dir) = git_dir {
+        git.current_dir(git_dir);
+    }
+    git.args(["rev-parse", rev]);
+    let output = git.output().map_err(|err| format!("{err:?}"))?;
+
+    match output.status.code() {
+        Some(0) => Ok(true),
+        Some(128) => Ok(false),
+        None => {
+            return Err(format!(
+                "git didn't exit properly: {}",
+                String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+            ));
+        }
+        Some(code) => {
+            return Err(format!(
+                "git command exited with status code: {code}: {}",
+                String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+            ));
+        }
+    }
+}
+
+/// Returns the master branch from which we can take diffs to see changes.
+/// This will usually be rust-lang/rust master, but sometimes this might not exist.
+/// This could be because the user is updating their forked master branch using the GitHub UI
+/// and therefore doesn't need an upstream master branch checked out.
+/// We will then fall back to origin/master in the hope that at least this exists.
+pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
+    let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
+    let upstream_master = format!("{upstream_remote}/master");
+    if rev_exists(&upstream_master, git_dir)? {
+        return Ok(upstream_master);
+    }
+
+    // We could implement smarter logic here in the future.
+    Ok("origin/master".into())
+}
diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs
new file mode 100644 (file)
index 0000000..d3d2323
--- /dev/null
@@ -0,0 +1,2 @@
+pub mod ci;
+pub mod git;
index aa346daf7e5f3a4b99d45b8440aab47507b095e4..530a80b1ed374523894a2a23c5775f2cf8b9d78d 100644 (file)
@@ -1,4 +1,4 @@
-use anyhow::Error;
+use anyhow::{Context, Error};
 use curl::easy::Easy;
 use indexmap::IndexMap;
 use std::collections::HashMap;
@@ -13,12 +13,13 @@ struct Tool {
     comments: Vec<String>,
 
     channel: Channel,
+    date: Option<String>,
     version: [u16; 3],
     checksums: IndexMap<String, String>,
 }
 
 impl Tool {
-    fn new() -> Result<Self, Error> {
+    fn new(date: Option<String>) -> Result<Self, Error> {
         let channel = match std::fs::read_to_string("src/ci/channel")?.trim() {
             "stable" => Channel::Stable,
             "beta" => Channel::Beta,
@@ -40,6 +41,7 @@ fn new() -> Result<Self, Error> {
         Ok(Self {
             channel,
             version,
+            date,
             config: existing.config,
             comments: existing.comments,
             checksums: IndexMap::new(),
@@ -84,7 +86,7 @@ fn detect_compiler(&mut self) -> Result<Stage0Toolchain, Error> {
             Channel::Nightly => "beta".to_string(),
         };
 
-        let manifest = fetch_manifest(&self.config, &channel)?;
+        let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?;
         self.collect_checksums(&manifest, COMPILER_COMPONENTS)?;
         Ok(Stage0Toolchain {
             date: manifest.date,
@@ -110,7 +112,7 @@ fn detect_rustfmt(&mut self) -> Result<Option<Stage0Toolchain>, Error> {
             return Ok(None);
         }
 
-        let manifest = fetch_manifest(&self.config, "nightly")?;
+        let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?;
         self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?;
         Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() }))
     }
@@ -141,16 +143,19 @@ fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Res
 }
 
 fn main() -> Result<(), Error> {
-    let tool = Tool::new()?;
+    let tool = Tool::new(std::env::args().nth(1))?;
     tool.update_json()?;
     Ok(())
 }
 
-fn fetch_manifest(config: &Config, channel: &str) -> Result<Manifest, Error> {
-    Ok(toml::from_slice(&http_get(&format!(
-        "{}/dist/channel-rust-{}.toml",
-        config.dist_server, channel
-    ))?)?)
+fn fetch_manifest(config: &Config, channel: &str, date: Option<&str>) -> Result<Manifest, Error> {
+    let url = if let Some(date) = date {
+        format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel)
+    } else {
+        format!("{}/dist/channel-rust-{}.toml", config.dist_server, channel)
+    };
+
+    Ok(toml::from_slice(&http_get(&url)?)?)
 }
 
 fn http_get(url: &str) -> Result<Vec<u8>, Error> {
@@ -164,7 +169,7 @@ fn http_get(url: &str) -> Result<Vec<u8>, Error> {
             data.extend_from_slice(new_data);
             Ok(new_data.len())
         })?;
-        transfer.perform()?;
+        transfer.perform().context(format!("failed to fetch {url}"))?;
     }
     Ok(data)
 }
index 2381cbdb4e9b07090f552d34a44a529b6e620e44..8c460b2237a6359a7e3335890db8da049bdd62fc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2381cbdb4e9b07090f552d34a44a529b6e620e44
+Subproject commit 8c460b2237a6359a7e3335890db8da049bdd62fc
index 903ee938d9d2d2f73e535c3b05eff4be2b628b49..02f3188f8be08209dfb700b07c7ceffe2ebd7670 100644 (file)
@@ -4203,6 +4203,7 @@ Released 2018-09-13
 [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 [`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
+[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check
 [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
@@ -4460,6 +4461,7 @@ Released 2018-09-13
 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
 [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
@@ -4545,6 +4547,7 @@ Released 2018-09-13
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
+[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
@@ -4590,6 +4593,7 @@ Released 2018-09-13
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
 [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
index e862f13e69fc7059011014ad82f3310e8666ea73..27cc5a1c3f04c5e53fc4008a18e611a2677035e2 100644 (file)
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
 
                         diag.span_suggestion(
                             expr.span,
-                            &format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
+                            format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
                             sugg,
                             rustc_errors::Applicability::HasPlaceholders,
                         );
@@ -68,7 +68,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
 fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let map = cx.tcx.hir();
     if_chain! {
-        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
+        if let Some(parent_id) = map.opt_parent_id(expr.hir_id);
         if let Some(parent) = map.find(parent_id);
         then {
             let expr = match parent {
index 3cd7d1d7e722833645876976a615e1d5a7de123f..2982460c9cfa49b6d2a4850eae3edd85a3daaa4f 100644 (file)
     crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
     crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
     crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
+    crate::fn_null_check::FN_NULL_CHECK_INFO,
     crate::format::USELESS_FORMAT_INFO,
     crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
     crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
     crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
     crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
     crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
+    crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
     crate::precedence::PRECEDENCE_INFO,
     crate::ptr::CMP_NULL_INFO,
     crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
     crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
     crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
     crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
+    crate::size_of_ref::SIZE_OF_REF_INFO,
     crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
     crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
     crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
     crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
     crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
     crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+    crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
     crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
index 7b43d8ccc67d1fec92a5be0389860e9c8c6658a5..f327c9a71b3c1f420e98fe502841ac60f1f58df4 100644 (file)
@@ -969,14 +969,14 @@ fn binding_ty_auto_deref_stability<'tcx>(
     precedence: i8,
     binder_args: &'tcx List<BoundVariableKind>,
 ) -> Position {
-    let TyKind::Rptr(_, ty) = &ty.kind else {
+    let TyKind::Ref(_, ty) = &ty.kind else {
         return Position::Other(precedence);
     };
     let mut ty = ty;
 
     loop {
         break match ty.ty.kind {
-            TyKind::Rptr(_, ref ref_ty) => {
+            TyKind::Ref(_, ref ref_ty) => {
                 ty = ref_ty;
                 continue;
             },
@@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
             possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
         }
         let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
-        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
-        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
-        // itself. See the comment in that method for an explanation as to why.
-        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+        // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
+        // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
+        // borrower of itself. See the comment in that method for an explanation as to why.
+        possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
             && used_exactly_once(mir, place.local).unwrap_or(false)
     } else {
         false
index 1d09adec12f3ffe7bdf58bb5785dc947aa86f0f9..dfb43893326eb8a225ee72b7ef0ce5feaecd0886 100644 (file)
@@ -131,7 +131,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
         _ => return false,
     }
 
-    matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_)))
+    matches!(map.find_parent(id), Some(Node::Param(_)))
 }
 
 impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
@@ -156,8 +156,8 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
             let map = &self.cx.tcx.hir();
             if is_argument(*map, cmt.hir_id) {
                 // Skip closure arguments
-                let parent_id = map.get_parent_node(cmt.hir_id);
-                if let Some(Node::Expr(..)) = map.find(map.get_parent_node(parent_id)) {
+                let parent_id = map.parent_id(cmt.hir_id);
+                if let Some(Node::Expr(..)) = map.find_parent(parent_id) {
                     return;
                 }
 
index 0ed301964758e643243ba19cb09f1f1ab37d2cbf..f95b628e6c31eb67b3bbd17e9b22534d0460ebe8 100644 (file)
@@ -324,7 +324,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
                     let maybe_neg_sugg = |expr, hir_id| {
                         let sugg = Sugg::hir(cx, expr, "..");
                         if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
-                            format!("-{sugg}")
+                            format!("-{}", sugg.maybe_par())
                         } else {
                             sugg.to_string()
                         }
diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs
new file mode 100644 (file)
index 0000000..91c8c34
--- /dev/null
@@ -0,0 +1,106 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for comparing a function pointer to null.
+    ///
+    /// ### Why is this bad?
+    /// Function pointers are assumed to not be null.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+    ///
+    /// if (fn_ptr as *const ()).is_null() { ... }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */
+    ///
+    /// if fn_ptr.is_none() { ... }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub FN_NULL_CHECK,
+    correctness,
+    "`fn()` type assumed to be nullable"
+}
+declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]);
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    span_lint_and_help(
+        cx,
+        FN_NULL_CHECK,
+        expr.span,
+        "function pointer assumed to be nullable, even though it isn't",
+        None,
+        "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value",
+    );
+}
+
+fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
+        && let TyKind::Ptr(_) = cast_ty.kind
+    {
+        cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn()
+    } else {
+        false
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        match expr.kind {
+            // Catching:
+            // (fn_ptr as *<const/mut> <ty>).is_null()
+            ExprKind::MethodCall(method_name, receiver, _, _)
+                if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) =>
+            {
+                lint_expr(cx, expr);
+            },
+
+            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+                let to_check: &Expr<'_>;
+                if is_fn_ptr_cast(cx, left) {
+                    to_check = right;
+                } else if is_fn_ptr_cast(cx, right) {
+                    to_check = left;
+                } else {
+                    return;
+                }
+
+                match to_check.kind {
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
+                    ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => {
+                        lint_expr(cx, expr);
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
+                    ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => {
+                        lint_expr(cx, expr);
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr>
+                    _ if matches!(
+                        constant(cx, cx.typeck_results(), to_check),
+                        Some((Constant::RawPtr(0), _))
+                    ) =>
+                    {
+                        lint_expr(cx, expr);
+                    },
+
+                    _ => {},
+                }
+            },
+            _ => {},
+        }
+    }
+}
index 69f7c152fc4af84ad6eb70ce628129babe33502f..043112bbc95967dc66c3814e3d02013ff76932cf 100644 (file)
@@ -382,7 +382,7 @@ fn check_format_in_format_args(
         call_site,
         &format!("`format!` in `{name}!` args"),
         |diag| {
-            diag.help(&format!(
+            diag.help(format!(
                 "combine the `format!(..)` arguments with the outer `{name}!(..)` call"
             ));
             diag.help("or consider changing `format!` to `format_args!`");
index 91e6ffe6447909d610bd14774b269c301c1eb0cf..9dbce3f889bef117ddfcbba93d9de08a85bd60bf 100644 (file)
     /// arguments but are not marked `unsafe`.
     ///
     /// ### Why is this bad?
-    /// The function should probably be marked `unsafe`, since
-    /// for an arbitrary raw pointer, there is no way of telling for sure if it is
-    /// valid.
+    /// The function should almost definitely be marked `unsafe`, since for an
+    /// arbitrary raw pointer, there is no way of telling for sure if it is valid.
+    ///
+    /// In general, this lint should **never be disabled** unless it is definitely a
+    /// false positive (please submit an issue if so) since it breaks Rust's
+    /// soundness guarantees, directly exposing API users to potentially dangerous
+    /// program behavior. This is also true for internal APIs, as it is easy to leak
+    /// unsoundness.
+    ///
+    /// ### Context
+    /// In Rust, an `unsafe {...}` block is used to indicate that the code in that
+    /// section has been verified in some way that the compiler can not. For a
+    /// function that accepts a raw pointer then accesses the pointer's data, this is
+    /// generally impossible as the incoming pointer could point anywhere, valid or
+    /// not. So, the signature should be marked `unsafe fn`: this indicates that the
+    /// function's caller must provide some verification that the arguments it sends
+    /// are valid (and then call the function within an `unsafe` block).
     ///
     /// ### Known problems
     /// * It does not check functions recursively so if the pointer is passed to a
     /// private non-`unsafe` function which does the dereferencing, the lint won't
-    /// trigger.
+    /// trigger (false negative).
     /// * It only checks for arguments whose type are raw pointers, not raw pointers
     /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
-    /// `some_argument.get_raw_ptr()`).
+    /// `some_argument.get_raw_ptr()`) (false negative).
     ///
     /// ### Example
     /// ```rust,ignore
     /// pub fn foo(x: *const u8) {
     ///     println!("{}", unsafe { *x });
     /// }
+    ///
+    /// // this call "looks" safe but will segfault or worse!
+    /// // foo(invalid_ptr);
     /// ```
     ///
     /// Use instead:
     /// pub unsafe fn foo(x: *const u8) {
     ///     println!("{}", unsafe { *x });
     /// }
+    ///
+    /// // this would cause a compiler error for calling without `unsafe`
+    /// // foo(invalid_ptr);
+    ///
+    /// // sound call if the caller knows the pointer is valid
+    /// unsafe { foo(valid_ptr); }
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NOT_UNSAFE_PTR_ARG_DEREF,
index cf35b1f175c602fd4fa70e677c1b202233968811..bdeddf44df7bd27839af48aa48ff7654794eb57b 100644 (file)
@@ -251,7 +251,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 let map = cx.tcx.hir();
 
                 // Checking for slice indexing
-                let parent_id = map.get_parent_node(expr.hir_id);
+                let parent_id = map.parent_id(expr.hir_id);
                 if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id);
                 if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind;
                 if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr);
@@ -259,7 +259,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 if index_value < max_suggested_slice;
 
                 // Make sure that this slice index is read only
-                let maybe_addrof_id = map.get_parent_node(parent_id);
+                let maybe_addrof_id = map.parent_id(parent_id);
                 if let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id);
                 if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind;
                 then {
index 76c83ab47d09561a9caf4ec22e161db2ce04ee18..db637dfc068d4840775e6909519d8616ff38a19f 100644 (file)
 }
 
 pub struct LargeConstArrays {
-    maximum_allowed_size: u64,
+    maximum_allowed_size: u128,
 }
 
 impl LargeConstArrays {
     #[must_use]
-    pub fn new(maximum_allowed_size: u64) -> Self {
+    pub fn new(maximum_allowed_size: u128) -> Self {
         Self { maximum_allowed_size }
     }
 }
@@ -56,7 +56,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
             if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
             if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
-            if self.maximum_allowed_size < element_count * element_size;
+            if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
 
             then {
                 let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
index b18456ee523401759104bbb383178e7d87b5cb5c..b8d4abdbb781acacba0f3910ff55526347ea8b9c 100644 (file)
@@ -111,7 +111,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
                         );
                         diag.span_label(
                             def.variants[variants_size[1].ind].span,
-                            &if variants_size[1].fields_size.is_empty() {
+                            if variants_size[1].fields_size.is_empty() {
                                 "the second-largest variant carries no data at all".to_owned()
                             } else {
                                 format!(
index 5857d81ab1f2094087cd5226850c748f4f160801..89ae83d48f536795f9aecc0d0de69a353d043177 100644 (file)
 }
 
 pub struct LargeStackArrays {
-    maximum_allowed_size: u64,
+    maximum_allowed_size: u128,
 }
 
 impl LargeStackArrays {
     #[must_use]
-    pub fn new(maximum_allowed_size: u64) -> Self {
+    pub fn new(maximum_allowed_size: u128) -> Self {
         Self { maximum_allowed_size }
     }
 }
@@ -45,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
           && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
           && !cx.tcx.hir().parent_iter(expr.hir_id)
               .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
-          && self.maximum_allowed_size < element_count * element_size {
+          && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) {
               span_lint_and_help(
                   cx,
                   LARGE_STACK_ARRAYS,
index e88d1764a24896a23d168a5b01c2d908e851e804..9eba46756299c57bc178a48fc92b65a4af99fc38 100644 (file)
@@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>(
             db.span_note(span, "`is_empty` defined here");
         }
         if let Some(self_kind) = self_kind {
-            db.note(&output.expected_sig(self_kind));
+            db.note(output.expected_sig(self_kind));
         }
     });
 }
index 39850d598038f1b3d15fce37e068528a3c9b1c8d..dcd8ca81ae87210dd1e033adec09e657274ded6a 100644 (file)
 mod fallible_impl_from;
 mod float_literal;
 mod floating_point_arithmetic;
+mod fn_null_check;
 mod format;
 mod format_args;
 mod format_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
 mod pattern_type_mismatch;
+mod permissions_set_readonly_false;
 mod precedence;
 mod ptr;
 mod ptr_offset_with_cast;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
+mod size_of_ref;
 mod slow_vector_initialization;
 mod std_instead_of_core;
 mod strings;
@@ -334,7 +337,7 @@ pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
         Ok(Some(path)) => path,
         Ok(None) => return Conf::default(),
         Err(error) => {
-            sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
+            sess.struct_err(format!("error finding Clippy's configuration file: {error}"))
                 .emit();
             return Conf::default();
         },
@@ -902,6 +905,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
     store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
+    store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
+    store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index 14f2234813277c7c5ae4226278798c26548aa012..1953ee8a717525a9ab3ac883bc0def758fa5875b 100644 (file)
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
                                 applicability,
                             );
 
-                            diag.note(&format!(
+                            diag.note(format!(
                                 "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
                             ));
                         },
index 07edee46fa657639fb29f0ddada7e638ff34cf1d..540656a2cd991d8f497e1531db137fd69bc2ed6d 100644 (file)
@@ -63,7 +63,7 @@ fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
                                 if let Node::Pat(pat) = node;
                                 if let PatKind::Binding(bind_ann, ..) = pat.kind;
                                 if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
-                                let parent_node = cx.tcx.hir().get_parent_node(hir_id);
+                                let parent_node = cx.tcx.hir().parent_id(hir_id);
                                 if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
                                 if let Some(init) = parent_let_expr.init;
                                 then {
index 075ecbe7eded37340c1b36db85654ea7996588dc..63212beaa63dd6b584685baf4650f718f8d0df2e 100644 (file)
@@ -76,7 +76,7 @@ fn check_fn(
                                 let help = format!("make the function `async` and {ret_sugg}");
                                 diag.span_suggestion(
                                     header_span,
-                                    &help,
+                                    help,
                                     format!("async {}{ret_snip}", &header_snip[..ret_pos]),
                                     Applicability::MachineApplicable
                                 );
@@ -152,7 +152,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
     let input_lifetimes: Vec<LifetimeName> = inputs
         .iter()
         .filter_map(|ty| {
-            if let TyKind::Rptr(lt, _) = ty.kind {
+            if let TyKind::Ref(lt, _) = ty.kind {
                 Some(lt.res)
             } else {
                 None
index bb6d628af3b5061f35c3a19e7df8498481c8ad5e..f239736d38a4cfdaf74cbe90a2c9ea127cb045fc 100644 (file)
@@ -35,6 +35,9 @@
     /// Some may consider panicking in these situations to be desirable, but it also may
     /// introduce panicking where there wasn't any before.
     ///
+    /// See also [the discussion in the
+    /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613).
+    ///
     /// ### Examples
     /// ```rust
     /// # let (input, min, max) = (0, -2, 1);
@@ -78,7 +81,7 @@
     /// ```
     #[clippy::version = "1.66.0"]
     pub MANUAL_CLAMP,
-    complexity,
+    nursery,
     "using a clamp pattern instead of the clamp function"
 }
 impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
index 8d447c37150b8d2a01f095755e878dbf13740b08..38f41d077c161f941764e897216d62c4fdd60b55 100644 (file)
@@ -74,7 +74,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             && let Some(hir_id) = path_to_local(expr3)
             && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) {
                 // Apply only to params or locals with annotated types
-                match cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+                match cx.tcx.hir().find_parent(hir_id) {
                     Some(Node::Param(..)) => (),
                     Some(Node::Local(local)) => {
                         let Some(ty) = local.ty else { return };
index de166b9765f4194b6ff22e909c8a370c3200146d..c795c1d9a16c321b9a9260df72206653d8516558 100644 (file)
@@ -109,7 +109,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
                     let test_span = expr.span.until(then.span);
                     span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
-                        diag.span_note(test_span, &format!("the {kind_word} was tested here"));
+                        diag.span_note(test_span, format!("the {kind_word} was tested here"));
                         multispan_sugg(
                             diag,
                             &format!("try using the `strip_{kind_word}` method"),
index d521a529e0d6463f12486033c3351d9218a67817..f6bf0e7aa1ad9bcfb17c896b116bdab9df215cae 100644 (file)
@@ -3,7 +3,7 @@
 use clippy_utils::visitors::contains_unsafe_block;
 use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
 
-use rustc_hir::LangItem::OptionSome;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{sym, SyntaxContext};
@@ -25,15 +25,13 @@ fn get_cond_expr<'tcx>(
         if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
         if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
         if let PatKind::Binding(_,target, ..) = pat.kind;
-        if let (then_visitor, else_visitor)
-            = (is_some_expr(cx, target, ctxt, then_expr),
-                is_some_expr(cx, target, ctxt, else_expr));
-        if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
+        if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
+            || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None`
         then {
             return Some(SomeExpr {
                     expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
                     needs_unsafe_block: contains_unsafe_block(cx, expr),
-                    needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
+                    needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond
                 })
             }
     };
@@ -74,6 +72,13 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr:
     false
 }
 
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+        return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
+    };
+    false
+}
+
 // given the closure: `|<pattern>| <expr>`
 // returns `|&<pattern>| <expr>`
 fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String {
index 1bf8d4e96ad49a8056a9208686c5cfd5f9acc3b1..065a5c72621cd50e1617c767874a01f361a41dfb 100644 (file)
@@ -31,19 +31,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
     };
 
     // Do we need to add ';' to suggestion ?
-    match match_body.kind {
-        ExprKind::Block(block, _) => {
-            // macro + expr_ty(body) == ()
-            if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
-                snippet_body.push(';');
-            }
-        },
-        _ => {
-            // expr_ty(body) == ()
-            if cx.typeck_results().expr_ty(match_body).is_unit() {
-                snippet_body.push(';');
-            }
-        },
+    if let ExprKind::Block(block, _) = match_body.kind {
+        // macro + expr_ty(body) == ()
+        if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
+            snippet_body.push(';');
+        }
     }
 
     let mut applicability = Applicability::MaybeIncorrect;
@@ -148,8 +140,8 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
 fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
     let map = &cx.tcx.hir();
 
-    if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)) {
-        return match map.find(map.get_parent_node(parent_arm_expr.hir_id)) {
+    if let Some(Node::Expr(parent_arm_expr)) = map.find_parent(ex.hir_id) {
+        return match map.find_parent(parent_arm_expr.hir_id) {
             Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
                 span: parent_let_expr.span,
                 pat_span: parent_let_expr.pat.span(),
@@ -191,8 +183,7 @@ fn sugg_with_curlies<'a>(
 
     // If the parent is already an arm, and the body is another match statement,
     // we need curly braces around suggestion
-    let parent_node_id = cx.tcx.hir().get_parent_node(match_expr.hir_id);
-    if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
+    if let Node::Arm(arm) = &cx.tcx.hir().get_parent(match_expr.hir_id) {
         if let ExprKind::Match(..) = arm.body.kind {
             cbrace_end = format!("\n{indent}}}");
             // Fix body indent due to the match
index 7f8d124838cb8be5a64b48f6c0c0f1febeca8ff4..59de8c0384ba0de464a4a0290983d75375f39b70 100644 (file)
@@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let mut has_non_wild = false;
     for arm in arms {
         match peel_hir_pat_refs(arm.pat).0.kind {
-            PatKind::Wild => wildcard_span = Some(arm.pat.span),
+            PatKind::Wild if arm.guard.is_none() => wildcard_span = Some(arm.pat.span),
             PatKind::Binding(_, _, ident, None) => {
                 wildcard_span = Some(arm.pat.span);
                 wildcard_ident = Some(ident);
index d8c821bc9eeee1cfb6eadf374a8c6e718668f472..424482859ee8797c2bced583be00c1e0e8696776 100644 (file)
@@ -36,7 +36,7 @@ pub fn check(
                 expr.span,
                 &format!("calling `to_string` on `{arg_ty}`"),
                 |diag| {
-                    diag.help(&format!(
+                    diag.help(format!(
                         "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
                     ));
                     let mut applicability = Applicability::MachineApplicable;
index beb772100affcb1e5f1351c413c0a656b0baeae7..279175e20c37fcd5126f908a4cd32ba4663e4a04 100644 (file)
@@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
                         application = Applicability::Unspecified;
                         diag.span_help(
                             pat.span,
-                            &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
+                            format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
                         );
                     }
                 }
index 561e4336593b047ed5f071e89c18f5ec6c82c69e..77be61b4793403d2a9ba489df6daab12103b8841 100644 (file)
@@ -3986,7 +3986,7 @@ fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
             (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
             (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
             (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
-            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
+            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Ref(_, _)),
             _ => false,
         }
     }
index 910ee14855e234d21507ff2ef01eb25061461bbb..4c6328481e438817cf82f843466ff3f406dc456f 100644 (file)
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
                 suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
             }
 
-            diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability);
+            diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability);
         });
     }
 }
index 3c01ce1fecd3a28a161625b72d63331405ff852a..d00708e828eaeb791391a8797bd6980d8e36399a 100644 (file)
@@ -167,7 +167,7 @@ fn check_manual_split_once_indirect(
             };
             diag.span_suggestion_verbose(
                 local.span,
-                &format!("try `{r}split_once`"),
+                format!("try `{r}split_once`"),
                 format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
                 app,
             );
index 0e73459ad65f7a258e91b6ee8ccd5ff50d7d4ded..47e2e744112c5a1dc89d29c1d27d0033a9edf3bf 100644 (file)
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
                     span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
                         diag.span_suggestion(
                             span,
-                            &format!("use `{simplify_using}(..)` instead"),
+                            format!("use `{simplify_using}(..)` instead"),
                             format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
                             applicability,
                         );
index 321fa4b7f9996681000b59321216a3474766df11..f0be7771bb1a6d6d44f2f7263915d251aa665d50 100644 (file)
@@ -186,7 +186,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
     let map = &vis.cx.tcx.hir();
     let mut cur_id = vis.write_expr.hir_id;
     loop {
-        let parent_id = map.get_parent_node(cur_id);
+        let parent_id = map.parent_id(cur_id);
         if parent_id == cur_id {
             break;
         }
index bc90e131b7f3be65b1ff008599796c50d5da7f7f..64d8333a093b1143047981a19414a00cb4c33dd5 100644 (file)
@@ -86,7 +86,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
             return;
         }
 
-        if let hir::TyKind::Rptr(
+        if let hir::TyKind::Ref(
             _,
             hir::MutTy {
                 ty: pty,
@@ -94,7 +94,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
             },
         ) = ty.kind
         {
-            if let hir::TyKind::Rptr(
+            if let hir::TyKind::Ref(
                 _,
                 hir::MutTy {
                     mutbl: hir::Mutability::Mut,
index f2ffac85bf4023cc25368595e239b84c7383f7e9..5457eeec4eacf249c2b1fef96d88f3e7a62da831 100644 (file)
@@ -124,7 +124,7 @@ fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
                     check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
                 }
             },
-            TyKind::Rptr(lifetime, mut_ty) => {
+            TyKind::Ref(lifetime, mut_ty) => {
                 if_chain! {
                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
                 if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
index 67debe7e08af6008c7ddf474c37a3c7a59e02614..5a9387b34cc1931a68adf7ae5f3fa013e3d72592 100644 (file)
@@ -284,7 +284,7 @@ fn check<'tcx>(
 
                     diag.span_suggestion(
                         assign.lhs_span,
-                        &format!("declare `{binding_name}` here"),
+                        format!("declare `{binding_name}` here"),
                         let_snippet,
                         Applicability::MachineApplicable,
                     );
@@ -304,7 +304,7 @@ fn check<'tcx>(
 
                     diag.span_suggestion_verbose(
                         usage.stmt.span.shrink_to_lo(),
-                        &format!("declare `{binding_name}` here"),
+                        format!("declare `{binding_name}` here"),
                         format!("{let_snippet} = "),
                         applicability,
                     );
@@ -335,7 +335,7 @@ fn check<'tcx>(
 
                     diag.span_suggestion_verbose(
                         usage.stmt.span.shrink_to_lo(),
-                        &format!("declare `{binding_name}` here"),
+                        format!("declare `{binding_name}` here"),
                         format!("{let_snippet} = "),
                         applicability,
                     );
index 2f0b7ce16e51b77541bdee6927dea53c98bdb18e..1249db5dc4792307ed353ba64dfd959e8a7368b4 100644 (file)
@@ -100,7 +100,7 @@ fn check_fn(
         }
 
         // Exclude non-inherent impls
-        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
index 2a3bd4ee6ce65cadcedac6ac19558d43ac6b269a..07fd321d69fced8a6ac11ebb3bb790a90fdf1bd3 100644 (file)
@@ -366,7 +366,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             let mut dereferenced_expr = expr;
             let mut needs_check_adjustment = true;
             loop {
-                let parent_id = cx.tcx.hir().get_parent_node(cur_expr.hir_id);
+                let parent_id = cx.tcx.hir().parent_id(cur_expr.hir_id);
                 if parent_id == cur_expr.hir_id {
                     break;
                 }
index ae0a41db918a3447067342479161c62939e71e9e..7376ab0c846d954c7c3c39e75b177a83e5f4ff82 100644 (file)
@@ -125,7 +125,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
             if is_string { "string" } else { "byte string" }
         ),
         |diag| {
-            diag.help(&format!(
+            diag.help(format!(
                 "octal escapes are not supported, `\\0` is always a null {}",
                 if is_string { "character" } else { "byte" }
             ));
@@ -139,7 +139,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
             // suggestion 2: unambiguous null byte
             diag.span_suggestion(
                 span,
-                &format!(
+                format!(
                     "if the null {} is intended, disambiguate using",
                     if is_string { "character" } else { "byte" }
                 ),
index ae805147f07a20155444857085a60eb120f604fe..015f6c14e7612f2c724711b9fed7f8786c433f02 100644 (file)
@@ -50,7 +50,7 @@ fn lint_misrefactored_assign_op(
                 let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
                 diag.span_suggestion(
                     expr.span,
-                    &format!(
+                    format!(
                         "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
                         op.as_str()
                     ),
index f9fd3645668a9959ee25a48f9fe46ba1fb9d5300..870a1c7d88d532bd6eadbf148acde49fd64b58be 100644 (file)
@@ -184,7 +184,7 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
                     if is_copy(cx, ty)
                         && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes())
                         && size <= self.ref_min_size
-                        && let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind
+                        && let hir::TyKind::Ref(_, MutTy { ty: decl_ty, .. }) = input.kind
                     {
                         if let Some(typeck) = cx.maybe_typeck_results() {
                             // Don't lint if an unsafe pointer is created.
@@ -299,7 +299,7 @@ fn check_fn(
         }
 
         // Exclude non-inherent impls
-        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
new file mode 100644 (file)
index 0000000..e7095ec
--- /dev/null
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`.
+    ///
+    /// ### Why is this bad?
+    /// On Unix platforms this results in the file being world writable,
+    /// equivalent to `chmod a+w <file>`.
+    /// ### Example
+    /// ```rust
+    /// use std::fs::File;
+    /// let f = File::create("foo.txt").unwrap();
+    /// let metadata = f.metadata().unwrap();
+    /// let mut permissions = metadata.permissions();
+    /// permissions.set_readonly(false);
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub PERMISSIONS_SET_READONLY_FALSE,
+    suspicious,
+    "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`"
+}
+declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]);
+
+impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
+            && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS)
+            && path.ident.name == sym!(set_readonly)
+            && let ExprKind::Lit(lit) = &arg.kind
+            && LitKind::Bool(false) == lit.node
+        {
+            span_lint_and_then(
+                cx,
+                PERMISSIONS_SET_READONLY_FALSE,
+                expr.span,
+                "call to `set_readonly` with argument `false`",
+                |diag| {
+                    diag.note("on Unix platforms this results in the file being world writable");
+                    diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\
+                        https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html");
+                }
+            );
+        }
+    }
+}
index e395ff54cb15a00f0693e6f8007f9d4ab1585aab..262953042581ab5269cb97221a946830c14059ef 100644 (file)
@@ -421,7 +421,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                 if let ty::Ref(_, ty, mutability) = *ty.kind();
                 if let ty::Adt(adt, substs) = *ty.kind();
 
-                if let TyKind::Rptr(lt, ref ty) = hir_ty.kind;
+                if let TyKind::Ref(lt, ref ty) = hir_ty.kind;
                 if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
 
                 // Check that the name as typed matches the actual name of the type.
@@ -503,14 +503,14 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
 
 fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&'tcx Body<'_>>) {
     if let FnRetTy::Return(ty) = sig.decl.output
-        && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
+        && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty)
     {
         let out_region = cx.tcx.named_region(out.hir_id);
         let args: Option<Vec<_>> = sig
             .decl
             .inputs
             .iter()
-            .filter_map(get_rptr_lm)
+            .filter_map(get_ref_lm)
             .filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region)
             .map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span))
             .collect();
@@ -704,8 +704,8 @@ fn matches_preds<'tcx>(
     })
 }
 
-fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
-    if let TyKind::Rptr(lt, ref m) = ty.kind {
+fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
+    if let TyKind::Ref(lt, ref m) = ty.kind {
         Some((lt, m.mutbl, ty.span))
     } else {
         None
index c1677fb3da1c4850215dfd6a88e1ee485d4c54ed..0e7c5cca7240bd02ba8a0523905de512d6930b8f 100644 (file)
@@ -131,7 +131,7 @@ fn check_fn(
                 // `res = clone(arg)` can be turned into `res = move arg;`
                 // if `arg` is the only borrow of `cloned` at this point.
 
-                if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
+                if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
                     continue;
                 }
 
@@ -178,7 +178,7 @@ fn check_fn(
                 // StorageDead(pred_arg);
                 // res = to_path_buf(cloned);
                 // ```
-                if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
+                if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
                     continue;
                 }
 
index 41f991a967bfd9929b025657ef21c8fc0aa573ca..44bf824aa0e2d432688e90827af89090640484dc 100644 (file)
@@ -59,7 +59,7 @@ fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
                 }
             },
             // This is what we are looking for !
-            TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
+            TyKind::Ref(ref optional_lifetime, ref borrow_type) => {
                 // Match the 'static lifetime
                 if let Some(lifetime) = *optional_lifetime {
                     match borrow_type.ty.kind {
index f21b3ea6c3b05b078d8ad92ea700fc302fb9d85e..448a32b77c036d92d2d5768db876c95c9317cbb6 100644 (file)
@@ -39,7 +39,7 @@
 impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
         if_chain! {
-            if let TyKind::Rptr(_, ref mut_ty) = ty.kind;
+            if let TyKind::Ref(_, ref mut_ty) = ty.kind;
             if mut_ty.mutbl == Mutability::Not;
             if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
             let last = last_path_segment(qpath);
@@ -52,7 +52,7 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
                 GenericArg::Type(inner_ty) => Some(inner_ty),
                 _ => None,
             });
-            if let TyKind::Rptr(_, ref inner_mut_ty) = inner_ty.kind;
+            if let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind;
             if inner_mut_ty.mutbl == Mutability::Not;
 
             then {
index 81143d7799ea8aa585f2e023b3cb9d3560dfd22f..d4d506605206b7734b6e2c0685d57f1bea663d29 100644 (file)
@@ -6,7 +6,7 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -207,6 +207,12 @@ fn check_final_expr<'tcx>(
     match &peeled_drop_expr.kind {
         // simple return is always "bad"
         ExprKind::Ret(ref inner) => {
+            // if desugar of `do yeet`, don't lint
+            if let Some(inner_expr) = inner
+                && let ExprKind::Call(path_expr, _) = inner_expr.kind
+                && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind {
+                    return;
+            }
             if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
                 let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                 if !borrows {
index caab5851bafc94ffe51fafb7d3ebf3d23f518fcc..17763128cd143bcbf9cc446e6cf3c9c72e6c3e0f 100644 (file)
@@ -108,7 +108,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
                                     |diag| {
                                         diag.span_note(
                                             trait_method_span,
-                                            &format!("existing `{method_name}` defined here"),
+                                            format!("existing `{method_name}` defined here"),
                                         );
                                     },
                                 );
@@ -151,7 +151,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
                                         // iterate on trait_spans?
                                         diag.span_note(
                                             trait_spans[0],
-                                            &format!("existing `{method_name}` defined here"),
+                                            format!("existing `{method_name}` defined here"),
                                         );
                                     },
                                 );
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
new file mode 100644 (file)
index 0000000..3fcdb42
--- /dev/null
@@ -0,0 +1,73 @@
+use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for calls to `std::mem::size_of_val()` where the argument is
+    /// a reference to a reference.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Calling `size_of_val()` with a reference to a reference as the argument
+    /// yields the size of the reference-type, not the size of the value behind
+    /// the reference.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct Foo {
+    ///     buffer: [u8],
+    /// }
+    ///
+    /// impl Foo {
+    ///     fn size(&self) -> usize {
+    ///         // Note that `&self` as an argument is a `&&Foo`: Because `self`
+    ///         // is already a reference, `&self` is a double-reference.
+    ///         // The return value of `size_of_val()` therefor is the
+    ///         // size of the reference-type, not the size of `self`.
+    ///         std::mem::size_of_val(&self)
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct Foo {
+    ///     buffer: [u8],
+    /// }
+    ///
+    /// impl Foo {
+    ///     fn size(&self) -> usize {
+    ///         // Correct
+    ///         std::mem::size_of_val(self)
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub SIZE_OF_REF,
+    suspicious,
+    "Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended"
+}
+declare_lint_pass!(SizeOfRef => [SIZE_OF_REF]);
+
+impl LateLintPass<'_> for SizeOfRef {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        if let ExprKind::Call(path, [arg]) = expr.kind
+            && let Some(def_id) = path_def_id(cx, path)
+            && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
+            && let arg_ty = cx.typeck_results().expr_ty(arg)
+            && peel_mid_ty_refs(arg_ty).1 > 1
+        {
+            span_lint_and_help(
+                cx,
+                SIZE_OF_REF,
+                expr.span,
+                "argument to `std::mem::size_of_val()` is a reference to a reference",
+                None,
+                "dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type",
+            );
+        }
+    }
+}
index c374529d1ea9f5abc9fd54bf49a36163c47463e7..17e9cc5f6b7c7a7d72a5fd73fed5f043c366708d 100644 (file)
@@ -132,7 +132,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
                 applicability,
             );
             if !is_xor_based {
-                diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?"));
+                diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
             }
         },
     );
@@ -214,7 +214,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
                                 Applicability::MaybeIncorrect,
                             );
                             diag.note(
-                                &format!("or maybe you should use `{sugg}::mem::replace`?")
+                                format!("or maybe you should use `{sugg}::mem::replace`?")
                             );
                         }
                     });
index 83e651aba8e89b15ed99db9dfcf768afece1431f..691d759d7739dbea81c65ab12c1a12855cda657e 100644 (file)
@@ -3,6 +3,7 @@
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
 mod transmute_int_to_float;
+mod transmute_null_to_fn;
 mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
     "transmutes from a null pointer to a reference, which is undefined behavior"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for null function pointer creation through transmute.
+    ///
+    /// ### Why is this bad?
+    /// Creating a null function pointer is undefined behavior.
+    ///
+    /// More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization
+    ///
+    /// ### Known problems
+    /// Not all cases can be detected at the moment of this writing.
+    /// For example, variables which hold a null pointer and are then fed to a `transmute`
+    /// call, aren't detectable yet.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let null_fn: Option<fn()> = None;
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub TRANSMUTE_NULL_TO_FN,
+    correctness,
+    "transmute results in a null function pointer, which is undefined behavior"
+}
+
 pub struct Transmute {
     msrv: Msrv,
 }
@@ -428,6 +457,7 @@ pub struct Transmute {
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
     TRANSMUTING_NULL,
+    TRANSMUTE_NULL_TO_FN,
 ]);
 impl Transmute {
     #[must_use]
@@ -461,6 +491,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
                     | crosspointer_transmute::check(cx, e, from_ty, to_ty)
                     | transmuting_null::check(cx, e, arg, to_ty)
+                    | transmute_null_to_fn::check(cx, e, arg, to_ty)
                     | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
new file mode 100644 (file)
index 0000000..e75d7f6
--- /dev/null
@@ -0,0 +1,64 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTE_NULL_TO_FN;
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    span_lint_and_then(
+        cx,
+        TRANSMUTE_NULL_TO_FN,
+        expr.span,
+        "transmuting a known null pointer into a function pointer",
+        |diag| {
+            diag.span_label(expr.span, "this transmute results in undefined behavior");
+            diag.help(
+               "try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value"
+            );
+        },
+    );
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+    if !to_ty.is_fn() {
+        return false;
+    }
+
+    match arg.kind {
+        // Catching:
+        // transmute over constants that resolve to `null`.
+        ExprKind::Path(ref _qpath)
+            if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) =>
+        {
+            lint_expr(cx, expr);
+            true
+        },
+
+        // Catching:
+        // `std::mem::transmute(0 as *const i32)`
+        ExprKind::Cast(inner_expr, _cast_ty) if is_integer_literal(inner_expr, 0) => {
+            lint_expr(cx, expr);
+            true
+        },
+
+        // Catching:
+        // `std::mem::transmute(std::ptr::null::<i32>())`
+        ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => {
+            lint_expr(cx, expr);
+            true
+        },
+
+        _ => {
+            // FIXME:
+            // Also catch transmutations of variables which are known nulls.
+            // To do this, MIR const propagation seems to be the better tool.
+            // Whenever MIR const prop routines are more developed, this will
+            // become available. As of this writing (25/03/19) it is not yet.
+            false
+        },
+    }
+}
index 3dde4eee67179fd9a394b10d5799b1d93ca04748..54ac04df1c12ab9bc96a5f1e8edf7aeb80ff60b5 100644 (file)
@@ -71,7 +71,7 @@ pub(super) fn check<'tcx>(
 /// Gets the type `Bar` in `…::transmute<Foo, &Bar>`.
 fn get_explicit_type<'tcx>(path: &'tcx Path<'tcx>) -> Option<&'tcx hir::Ty<'tcx>> {
     if let GenericArg::Type(ty) = path.segments.last()?.args?.args.get(1)?
-        && let TyKind::Rptr(_, ty) = &ty.kind
+        && let TyKind::Ref(_, ty) = &ty.kind
     {
         Some(ty.ty)
     } else {
index 34642f4b122f22f097df02fada46a66a69129192..af0242348ac295facaeff4a24e661b6c8863e3e6 100644 (file)
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty.peel_refs() {
-                            diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
                         }
                     },
                 );
@@ -91,7 +91,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute to `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty.peel_refs() {
-                            diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
                         }
                     },
                 );
@@ -119,16 +119,16 @@ pub(super) fn check<'tcx>(
                     ),
                     |diag| {
                         if let Some(same_adt_did) = same_adt_did {
-                            diag.note(&format!(
+                            diag.note(format!(
                                 "two instances of the same generic type (`{}`) may have different layouts",
                                 cx.tcx.item_name(same_adt_did)
                             ));
                         } else {
                             if from_ty_orig.peel_refs() != from_ty {
-                                diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                                diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
                             }
                             if to_ty_orig.peel_refs() != to_ty {
-                                diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                                diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
                             }
                         }
                     },
@@ -146,7 +146,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty {
-                            diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
                         }
                     },
                 );
@@ -163,7 +163,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute into `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty {
-                            diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
                         }
                     },
                 );
index 6b444922a7cc755b7907a28a12617dc6eacb2ede..b79d4e915a2718b70ae063b686aa7ad66918ddd0 100644 (file)
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
             &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
             |diag| {
                 if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                    let sugg = arg.as_ty(&to_ty.to_string()).to_string();
+                    let sugg = arg.as_ty(to_ty.to_string()).to_string();
                     diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
                 }
             },
index 19ce5ae72c24e8f7b21dd162fc9dcd29e8d81bd0..1e407fc4138c1ecbcc184c611170b7c754e6c043 100644 (file)
@@ -18,8 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     // Catching transmute over constants that resolve to `null`.
     let mut const_eval_context = constant_context(cx, cx.typeck_results());
     if let ExprKind::Path(ref _qpath) = arg.kind &&
-        let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) &&
-        x == 0
+        let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
index f919bbd5afca3f823c9458c815ae7f8fab5e9fbe..871c3fadbba71b84f7c1d18364f44fb40fb9293f 100644 (file)
@@ -61,7 +61,7 @@ pub(super) fn check<'tcx>(
                 "transmute from an integer to a pointer",
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified);
+                        diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified);
                     }
                 },
             );
index 20978e81dc584619c5ade53fc1f15b806920fdf1..c14f056a1f2de181d41e47a99bdcbc2c09338ac1 100644 (file)
@@ -539,7 +539,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, mut context:
                     QPath::LangItem(..) => {},
                 }
             },
-            TyKind::Rptr(lt, ref mut_ty) => {
+            TyKind::Ref(lt, ref mut_ty) => {
                 context.is_nested_call = true;
                 if !borrowed_box::check(cx, hir_ty, lt, mut_ty) {
                     self.check_ty(cx, mut_ty.ty, context);
index fae5385ffc848dc3d09805baac4d749f3fc5dfc4..f9b9a66b5fa461b17e2e99dd41da1dfd8192ccaf 100644 (file)
@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             &format!("usage of `{outer_sym}<{generic_snippet}>`"),
             |diag| {
                 diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
-                diag.note(&format!(
+                diag.note(format!(
                     "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
                 ));
             },
@@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                     format!("{outer_sym}<{generic_snippet}>"),
                     applicability,
                 );
-                diag.note(&format!(
+                diag.note(format!(
                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
                 ));
             },
@@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             hir_ty.span,
             &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
             |diag| {
-                diag.note(&format!(
+                diag.note(format!(
                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
                 ));
-                diag.help(&format!(
+                diag.help(format!(
                     "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
                 ));
             },
index 5ca4023aa5c199b3d8d2296525b2f2eb5640057b..0aa50c99c16904abed7bfd0c3ddb278a11877264 100644 (file)
@@ -44,7 +44,7 @@ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
         let (add_score, sub_nest) = match ty.kind {
             // _, &x and *x have only small overhead; don't mess with nesting level
-            TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
+            TyKind::Infer | TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0),
 
             // the "normal" components of a type: named types, arrays/tuples
             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
index 0fa75f8f0a9be3e7c06632da3bd8bb0a7988fe37..7f43b7841ff33d887668c2b321e686db081d9d76 100644 (file)
@@ -13,7 +13,7 @@ pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>)
             GenericArg::Type(ty) => Some(ty),
             _ => None,
         });
-        if let TyKind::Rptr(..) = ty.kind;
+        if let TyKind::Ref(..) = ty.kind;
         then {
             return Some(ty.span);
         }
index f6d3fb00f4ee5220926e4ffe3c261fc1d9a4a42f..dd120599c04e1b9c6f0175a4644e4c14dd1b00c8 100644 (file)
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         return;
     }
     let map = &cx.tcx.hir();
-    let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
+    let opt_parent_node = map.find_parent(expr.hir_id);
     if_chain! {
         if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
         if is_questionmark_desugar_marked_call(parent_expr);
@@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
 
                 if arg_snippets_without_empty_blocks.is_empty() {
                     db.multipart_suggestion(
-                        &format!("use {singular}unit literal{plural} instead"),
+                        format!("use {singular}unit literal{plural} instead"),
                         args_to_recover
                             .iter()
                             .map(|arg| (arg.span, "()".to_string()))
@@ -142,7 +142,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
                     let it_or_them = if plural { "them" } else { "it" };
                     db.span_suggestion(
                         expr.span,
-                        &format!(
+                        format!(
                             "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`"
                         ),
                         sugg,
@@ -192,7 +192,7 @@ fn fmt_stmts_and_call(
 
     let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
     // expr is not in a block statement or result expression position, wrap in a block
-    let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id));
+    let parent_node = cx.tcx.hir().find_parent(call_expr.hir_id);
     if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
         let block_indent = call_expr_indent + 4;
         stmts_and_call_snippet =
index 60b46854b4ffebb2fa84bcd8f721e19a76c2d330..84ec0d0fb1cf4ccf42e4bf43e8b4c34f84d192c1 100644 (file)
@@ -91,7 +91,7 @@ fn check_fn(
         }
 
         // Abort if the method is implementing a trait or of it a trait method.
-        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
index 3743d5d97a73585e50d2eabe9a312c3808ddfd3d..a95e7b613746dbfc33bb02f1df7a02bc13ef4179 100644 (file)
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
-use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -81,16 +81,24 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     }
                 }
                 if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter {
-                    if let Some(parent_expr) = get_parent_expr(cx, e) {
-                        if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind {
-                            if parent_name.ident.name != sym::into_iter {
-                                return;
-                            }
-                        }
+                    if get_parent_expr(cx, e).is_some() &&
+                       let Some(id) = path_to_local(recv) &&
+                       let Node::Pat(pat) = cx.tcx.hir().get(id) &&
+                       let PatKind::Binding(ann, ..) = pat.kind &&
+                       ann != BindingAnnotation::MUT
+                    {
+                        // Do not remove .into_iter() applied to a non-mutable local variable used in
+                        // a larger expression context as it would differ in mutability.
+                        return;
                     }
+
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
-                    if same_type_and_consts(a, b) {
+
+                    // If the types are identical then .into_iter() can be removed, unless the type
+                    // implements Copy, in which case .into_iter() returns a copy of the receiver and
+                    // cannot be safely omitted.
+                    if same_type_and_consts(a, b) && !is_copy(cx, b) {
                         let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
index 3e7d0028c0fbd97df2a73e40300db80ac39606fe..c1589c771c462f6379ac9e3f16bfd0fb4b86fb08 100644 (file)
@@ -333,7 +333,7 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
     ///
     /// The maximum allowed size for arrays on the stack
-    (array_size_threshold: u64 = 512_000),
+    (array_size_threshold: u128 = 512_000),
     /// Lint: VEC_BOX.
     ///
     /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
index 786d9608c851ee1001e1c59c36c1a0911e313544..4c3b1b131fd4caeea3f8d3951382f1a02defd374 100644 (file)
@@ -257,7 +257,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
 }
 
 pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
-    if let TyKind::Rptr(
+    if let TyKind::Ref(
         _,
         MutTy {
             ty: inner,
index 857abe77e21f239c6225a1dd06b6d45348d38d5b..c86f24cbd3780d5300ad1b4d278668e125d8ddf9 100644 (file)
@@ -558,8 +558,8 @@ impl fmt::Display for ClippyConfiguration {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
         writeln!(
             f,
-            "* `{}`: `{}`: {} (defaults to `{}`)",
-            self.name, self.config_type, self.doc, self.default
+            "* `{}`: `{}`(defaults to `{}`): {}",
+            self.name, self.config_type, self.default, self.doc
         )
     }
 }
@@ -1058,7 +1058,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
 fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     let map = cx.tcx.hir();
 
-    match map.find(map.get_parent_node(hir_id)) {
+    match map.find_parent((hir_id)) {
         Some(hir::Node::Local(local)) => Some(local),
         Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
         _ => None,
index 393988dbad384c5584f7db19f511995d70ce39b6..7144363637a04a0d0213c7b9d696431605a61450 100644 (file)
@@ -219,7 +219,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
     match peel_hir_expr_refs(expr).0.kind {
         ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
             Res::Local(hir_id) => {
-                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
+                let parent_id = cx.tcx.hir().parent_id(hir_id);
                 if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
                     path_to_matched_type(cx, init)
                 } else {
index 6b321765bc082d8c1912bd1413e9dfdbee71e059..df3350388817ed9ca3765d3bd6c1a45882611353 100644 (file)
@@ -377,7 +377,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
                     // print!("\n"), write!(f, "\n")
 
                     diag.multipart_suggestion(
-                        &format!("use `{name}ln!` instead"),
+                        format!("use `{name}ln!` instead"),
                         vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
                         Applicability::MachineApplicable,
                     );
@@ -388,7 +388,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
                     let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
 
                     diag.multipart_suggestion(
-                        &format!("use `{name}ln!` instead"),
+                        format!("use `{name}ln!` instead"),
                         vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
                         Applicability::MachineApplicable,
                     );
index 49e5f283db08904b5e273449a9f3696343dcab3a..9d0263e93be756939d9e7df6c36f50e7169f6d8e 100644 (file)
@@ -625,7 +625,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
         (Slice(l), Slice(r)) => eq_ty(l, r),
         (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
         (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
-        (Rptr(ll, l), Rptr(rl, r)) => {
+        (Ref(ll, l), Ref(rl, r)) => {
             both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
         },
         (BareFn(l), BareFn(r)) => {
index 7a637d32babecab6656bd5705f5dbf1873449f60..a67bd8d46006b7343be74e968ac9c5c30eb35ce6 100644 (file)
@@ -620,12 +620,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
                 ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
                     int.try_into().expect("invalid f64 bit representation"),
                 ))),
-                ty::RawPtr(type_and_mut) => {
-                    if let ty::Uint(_) = type_and_mut.ty.kind() {
-                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
-                    }
-                    None
-                },
+                ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
                 // FIXME: implement other conversions.
                 _ => None,
             }
index 16b160b6fd27ef688b888d8e9fbd9cee5d2da35b..812f6fe71a0a0c7faf9efd8b002055072082dafb 100644 (file)
@@ -17,7 +17,7 @@
 fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
     if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
         if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
-            diag.help(&format!(
+            diag.help(format!(
                 "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
                 &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                     // extract just major + minor version and ignore patch versions
index 07fb6af91ba042f8a6372abb74171233ea891eb3..2bbe1a19b625a7e7eb19c77e88a8a8f2c8e566a5 100644 (file)
@@ -430,7 +430,7 @@ pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
             (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_array_length(ll, rl),
             (TyKind::Ptr(l_mut), TyKind::Ptr(r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty),
-            (TyKind::Rptr(_, l_rmut), TyKind::Rptr(_, r_rmut)) => {
+            (TyKind::Ref(_, l_rmut), TyKind::Ref(_, r_rmut)) => {
                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty)
             },
             (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
@@ -950,7 +950,7 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
                 self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
-            TyKind::Rptr(lifetime, ref mut_ty) => {
+            TyKind::Ref(lifetime, ref mut_ty) => {
                 self.hash_lifetime(lifetime);
                 self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
index 43e2d1ec826c2343b9d6dea43c11ae3fe3789917..8290fe9ecb4c64593098395ff34389aa30ec4c06 100644 (file)
@@ -174,7 +174,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
     if_chain! {
         if let Some(Node::Pat(pat)) = hir.find(hir_id);
         if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
-        let parent = hir.get_parent_node(hir_id);
+        let parent = hir.parent_id(hir_id);
         if let Some(Node::Local(local)) = hir.find(parent);
         then {
             return local.init;
@@ -1287,7 +1287,7 @@ pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
 
 /// Gets the parent node, if any.
 pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
-    tcx.hir().parent_iter(id).next().map(|(_, node)| node)
+    tcx.hir().find_parent(id)
 }
 
 /// Gets the parent expression, if any –- this is useful to constrain a lint.
@@ -2075,7 +2075,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
 /// }
 /// ```
 pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
-    if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
+    if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
         matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
     } else {
         false
@@ -2264,7 +2264,7 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
     let mut count = 0;
     loop {
         match &ty.kind {
-            TyKind::Rptr(_, ref_ty) => {
+            TyKind::Ref(_, ref_ty) => {
                 ty = ref_ty.ty;
                 count += 1;
             },
diff --git a/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs b/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
deleted file mode 100644 (file)
index d262b33..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir;
-use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
-
-/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
-#[derive(Copy, Clone)]
-pub(super) struct MaybeStorageLive;
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Domain = BitSet<mir::Local>;
-    const NAME: &'static str = "maybe_storage_live";
-
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        // bottom = dead
-        BitSet::new_empty(body.local_decls.len())
-    }
-
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
-        for arg in body.args_iter() {
-            state.insert(arg);
-        }
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
-    type Idx = mir::Local;
-
-    fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
-        match stmt.kind {
-            mir::StatementKind::StorageLive(l) => trans.gen(l),
-            mir::StatementKind::StorageDead(l) => trans.kill(l),
-            _ => (),
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        _loc: mir::Location,
-    ) {
-    }
-
-    fn call_return_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _return_places: CallReturnPlaces<'_, 'tcx>,
-    ) {
-        // Nothing to do when a call returns successfully
-    }
-}
index 818e603f665e7d55422db9b3879a7dd1829a566a..26c0015e87e0fb1aeab8e20f0c21faf6498c940c 100644 (file)
@@ -5,8 +5,6 @@
 };
 use rustc_middle::ty::TyCtxt;
 
-mod maybe_storage_live;
-
 mod possible_borrower;
 pub use possible_borrower::PossibleBorrowerMap;
 
index 25717bf3d2fee5329bffe8128ed66a95acdf3904..395d46e7a2f8af088f359177ebe4ebf4f4e08c39 100644 (file)
-use super::{
-    maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
-    transitive_relation::TransitiveRelation,
-};
+use super::possible_origin::PossibleOriginVisitor;
 use crate::ty::is_copy;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_lint::LateContext;
-use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
-use rustc_middle::ty::{self, visit::TypeVisitor};
-use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use rustc_middle::mir::{
+    self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
+};
+use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
+use rustc_mir_dataflow::{
+    fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
+    CallReturnPlaces, ResultsCursor,
+};
+use std::borrow::Cow;
 use std::ops::ControlFlow;
 
 /// Collects the possible borrowers of each local.
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
 #[allow(clippy::module_name_repetitions)]
-struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
-    possible_borrower: TransitiveRelation,
+struct PossibleBorrowerAnalysis<'b, 'tcx> {
+    tcx: TyCtxt<'tcx>,
     body: &'b mir::Body<'tcx>,
-    cx: &'a LateContext<'tcx>,
     possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
 }
 
-impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
-    fn new(
-        cx: &'a LateContext<'tcx>,
-        body: &'b mir::Body<'tcx>,
-        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    ) -> Self {
+#[derive(Clone, Debug, Eq, PartialEq)]
+struct PossibleBorrowerState {
+    map: FxIndexMap<Local, BitSet<Local>>,
+    domain_size: usize,
+}
+
+impl PossibleBorrowerState {
+    fn new(domain_size: usize) -> Self {
         Self {
-            possible_borrower: TransitiveRelation::default(),
-            cx,
-            body,
-            possible_origin,
+            map: FxIndexMap::default(),
+            domain_size,
         }
     }
 
-    fn into_map(
-        self,
-        cx: &'a LateContext<'tcx>,
-        maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
-    ) -> PossibleBorrowerMap<'b, 'tcx> {
-        let mut map = FxHashMap::default();
-        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
-            if is_copy(cx, self.body.local_decls[row].ty) {
-                continue;
-            }
+    #[allow(clippy::similar_names)]
+    fn add(&mut self, borrowed: Local, borrower: Local) {
+        self.map
+            .entry(borrowed)
+            .or_insert(BitSet::new_empty(self.domain_size))
+            .insert(borrower);
+    }
+}
 
-            let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
-            borrowers.remove(mir::Local::from_usize(0));
+impl<C> DebugWithContext<C> for PossibleBorrowerState {
+    fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        <_ as std::fmt::Debug>::fmt(self, f)
+    }
+    fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        unimplemented!()
+    }
+}
+
+impl JoinSemiLattice for PossibleBorrowerState {
+    fn join(&mut self, other: &Self) -> bool {
+        let mut changed = false;
+        for (&borrowed, borrowers) in other.map.iter() {
             if !borrowers.is_empty() {
-                map.insert(row, borrowers);
+                changed |= self
+                    .map
+                    .entry(borrowed)
+                    .or_insert(BitSet::new_empty(self.domain_size))
+                    .union(borrowers);
             }
         }
+        changed
+    }
+}
 
-        let bs = BitSet::new_empty(self.body.local_decls.len());
-        PossibleBorrowerMap {
-            map,
-            maybe_live,
-            bitset: (bs.clone(), bs),
+impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
+    type Domain = PossibleBorrowerState;
+
+    const NAME: &'static str = "possible_borrower";
+
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        PossibleBorrowerState::new(body.local_decls.len())
+    }
+
+    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
+}
+
+impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        body: &'b mir::Body<'tcx>,
+        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+    ) -> Self {
+        Self {
+            tcx,
+            body,
+            possible_origin,
         }
     }
 }
 
-impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
-    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
-        let lhs = place.local;
-        match rvalue {
-            mir::Rvalue::Ref(_, _, borrowed) => {
-                self.possible_borrower.add(borrowed.local, lhs);
-            },
-            other => {
-                if ContainsRegion
-                    .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
-                    .is_continue()
-                {
-                    return;
-                }
-                rvalue_locals(other, |rhs| {
-                    if lhs != rhs {
-                        self.possible_borrower.add(rhs, lhs);
+impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
+    fn apply_call_return_effect(
+        &self,
+        _state: &mut Self::Domain,
+        _block: BasicBlock,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+    }
+
+    fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
+        if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
+            let lhs = place.local;
+            match rvalue {
+                mir::Rvalue::Ref(_, _, borrowed) => {
+                    state.add(borrowed.local, lhs);
+                },
+                other => {
+                    if ContainsRegion
+                        .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
+                        .is_continue()
+                    {
+                        return;
                     }
-                });
-            },
+                    rvalue_locals(other, |rhs| {
+                        if lhs != rhs {
+                            state.add(rhs, lhs);
+                        }
+                    });
+                },
+            }
         }
     }
 
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
+    fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
         if let mir::TerminatorKind::Call {
             args,
             destination: mir::Place { local: dest, .. },
@@ -126,10 +171,10 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Loca
 
             for y in mutable_variables {
                 for x in &immutable_borrowers {
-                    self.possible_borrower.add(*x, y);
+                    state.add(*x, y);
                 }
                 for x in &mutable_borrowers {
-                    self.possible_borrower.add(*x, y);
+                    state.add(*x, y);
                 }
             }
         }
@@ -165,73 +210,98 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
     }
 }
 
-/// Result of `PossibleBorrowerVisitor`.
+/// Result of `PossibleBorrowerAnalysis`.
 #[allow(clippy::module_name_repetitions)]
 pub struct PossibleBorrowerMap<'b, 'tcx> {
-    /// Mapping `Local -> its possible borrowers`
-    pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
-    // Caches to avoid allocation of `BitSet` on every query
-    pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
+    body: &'b mir::Body<'tcx>,
+    possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
+    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
+    pushed: BitSet<Local>,
+    stack: Vec<Local>,
 }
 
-impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
-    pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+    pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
         let possible_origin = {
             let mut vis = PossibleOriginVisitor::new(mir);
             vis.visit_body(mir);
             vis.into_map(cx)
         };
-        let maybe_storage_live_result = MaybeStorageLive
+        let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
             .into_engine(cx.tcx, mir)
-            .pass_name("redundant_clone")
+            .pass_name("possible_borrower")
             .iterate_to_fixpoint()
             .into_results_cursor(mir);
-        let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
-        vis.visit_body(mir);
-        vis.into_map(cx, maybe_storage_live_result)
-    }
-
-    /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
-    pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
-        self.bounded_borrowers(borrowers, borrowers, borrowed, at)
+        let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
+            .into_engine(cx.tcx, mir)
+            .pass_name("possible_borrower")
+            .iterate_to_fixpoint()
+            .into_results_cursor(mir);
+        PossibleBorrowerMap {
+            body: mir,
+            possible_borrower,
+            maybe_live,
+            pushed: BitSet::new_empty(mir.local_decls.len()),
+            stack: Vec::with_capacity(mir.local_decls.len()),
+        }
     }
 
-    /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
-    /// but no more than `above`.
-    pub fn bounded_borrowers(
+    /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
+    /// `borrowers`.
+    /// Notes:
+    /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
+    /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
+    /// `Dereferencing`, which outlives any `LateContext`.
+    /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
+    /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
+    /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
+    /// adjusted.
+    pub fn at_most_borrowers(
         &mut self,
-        below: &[mir::Local],
-        above: &[mir::Local],
+        cx: &LateContext<'tcx>,
+        borrowers: &[mir::Local],
         borrowed: mir::Local,
         at: mir::Location,
     ) -> bool {
-        self.maybe_live.seek_after_primary_effect(at);
+        if is_copy(cx, self.body.local_decls[borrowed].ty) {
+            return true;
+        }
 
-        self.bitset.0.clear();
-        let maybe_live = &mut self.maybe_live;
-        if let Some(bitset) = self.map.get(&borrowed) {
-            for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
-                self.bitset.0.insert(b);
+        self.possible_borrower.seek_before_primary_effect(at);
+        self.maybe_live.seek_before_primary_effect(at);
+
+        let possible_borrower = &self.possible_borrower.get().map;
+        let maybe_live = &self.maybe_live;
+
+        self.pushed.clear();
+        self.stack.clear();
+
+        if let Some(borrowers) = possible_borrower.get(&borrowed) {
+            for b in borrowers.iter() {
+                if self.pushed.insert(b) {
+                    self.stack.push(b);
+                }
             }
         } else {
-            return false;
+            // Nothing borrows `borrowed` at `at`.
+            return true;
         }
 
-        self.bitset.1.clear();
-        for b in below {
-            self.bitset.1.insert(*b);
-        }
-
-        if !self.bitset.0.superset(&self.bitset.1) {
-            return false;
-        }
+        while let Some(borrower) = self.stack.pop() {
+            if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
+                return false;
+            }
 
-        for b in above {
-            self.bitset.0.remove(*b);
+            if let Some(borrowers) = possible_borrower.get(&borrower) {
+                for b in borrowers.iter() {
+                    if self.pushed.insert(b) {
+                        self.stack.push(b);
+                    }
+                }
+            }
         }
 
-        self.bitset.0.is_empty()
+        true
     }
 
     pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
index b66604f33db1799d49b8fd5fb9b3ccfaa40fa1f1..e7879bb196e428d3597b88d52d8d30fe83df6414 100644 (file)
@@ -185,7 +185,6 @@ pub fn ast(
     ) -> Self {
         use rustc_ast::ast::RangeLimits;
 
-        #[expect(clippy::match_wildcard_for_single_variants)]
         match expr.kind {
             _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
             ast::ExprKind::AddrOf(..)
@@ -813,9 +812,9 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
         let closure_body = cx.tcx.hir().body(body);
         // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
         // a type annotation is present if param `kind` is different from `TyKind::Infer`
-        let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
+        let closure_arg_is_type_annotated_double_ref = if let TyKind::Ref(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
         {
-            matches!(ty.kind, TyKind::Rptr(_, MutTy { .. }))
+            matches!(ty.kind, TyKind::Ref(_, MutTy { .. }))
         } else {
             false
         };
index 2773da70d7880c2b387b96bfebabe33963051adb..c8d56a3be5cf356ca7c3723dd8cb29fbed2fbf79 100644 (file)
@@ -496,7 +496,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo
 /// Returns the base type for HIR references and pointers.
 pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
     match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
+        TyKind::Ptr(ref mut_ty) | TyKind::Ref(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
         _ => ty,
     }
 }
index 8e21cef32abb63ff135e93acb27ef0d644e97de9..9399d422036d47e3662958ad992b8fd2080ef989 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-17"
+channel = "nightly-2022-12-29"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 92ba3592967803c41235fd84b4a418528a3bf376..22ce1c6f6471b541dad4a7dda9b87aadb484db7c 100644 (file)
@@ -3,8 +3,7 @@ error: an async construct yields a type which is itself awaitable
    |
 LL |        let _h = async {
    |  _____________________-
-LL | |          async {
-   | | _________^
+LL | |/         async {
 LL | ||             3
 LL | ||         }
    | ||_________^ awaitable value not awaited
@@ -37,8 +36,7 @@ error: an async construct yields a type which is itself awaitable
    |
 LL |        let _j = async || {
    |  ________________________-
-LL | |          async {
-   | | _________^
+LL | |/         async {
 LL | ||             3
 LL | ||         }
    | ||_________^ awaitable value not awaited
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.rs b/src/tools/clippy/tests/ui/crashes/ice-10044.rs
new file mode 100644 (file)
index 0000000..65f38fe
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    [0; usize::MAX];
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.stderr b/src/tools/clippy/tests/ui/crashes/ice-10044.stderr
new file mode 100644 (file)
index 0000000..731f826
--- /dev/null
@@ -0,0 +1,10 @@
+error: statement with no effect
+  --> $DIR/ice-10044.rs:2:5
+   |
+LL |     [0; usize::MAX];
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::no-effect` implied by `-D warnings`
+
+error: aborting due to previous error
+
index 884d05fed71ba2f650100a8e1db301ac3c5731e7..8ffd4cc513790fca6400282d63694f513b97eef4 100644 (file)
@@ -14,6 +14,15 @@ fn main() {
     let _ = (y as f32).mul_add(y as f32, x);
     let _ = x.mul_add(x, y).sqrt();
     let _ = y.mul_add(y, x).sqrt();
+
+    let _ = (x - 1.0).mul_add(x - 1.0, -y);
+    let _ = (x - 1.0).mul_add(x - 1.0, -y) + 3.0;
+    let _ = (x - 1.0).mul_add(x - 1.0, -(y + 3.0));
+    let _ = (y + 1.0).mul_add(-(y + 1.0), x);
+    let _ = (3.0 * y).mul_add(-(3.0 * y), x);
+    let _ = (y + 1.0 + x).mul_add(-(y + 1.0 + x), x);
+    let _ = (y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powi(2);
     let _ = x.powi(1 + 1);
index e6a1c895371b6fe68622774068b4a693798350b8..9ae3455a1346a8aea6ffd4ce07025504b4bf2fbb 100644 (file)
@@ -14,6 +14,15 @@ fn main() {
     let _ = x + (y as f32).powi(2);
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
+
+    let _ = (x - 1.0).powi(2) - y;
+    let _ = (x - 1.0).powi(2) - y + 3.0;
+    let _ = (x - 1.0).powi(2) - (y + 3.0);
+    let _ = x - (y + 1.0).powi(2);
+    let _ = x - (3.0 * y).powi(2);
+    let _ = x - (y + 1.0 + x).powi(2);
+    let _ = x - (y + 1.0 + 2.0).powi(2);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powi(2);
     let _ = x.powi(1 + 1);
index 5df0de1fef22e59f22fdf21d73e5c6e2ed7bed69..fdf6d088052ea59bf62b732a711120bd15a6a6d1 100644 (file)
@@ -42,5 +42,47 @@ error: multiply and add expressions can be calculated more efficiently and accur
 LL |     let _ = (x + y.powi(2)).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 7 previous errors
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:18:13
+   |
+LL |     let _ = (x - 1.0).powi(2) - y;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:19:13
+   |
+LL |     let _ = (x - 1.0).powi(2) - y + 3.0;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:20:13
+   |
+LL |     let _ = (x - 1.0).powi(2) - (y + 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -(y + 3.0))`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:21:13
+   |
+LL |     let _ = x - (y + 1.0).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0).mul_add(-(y + 1.0), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:22:13
+   |
+LL |     let _ = x - (3.0 * y).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(3.0 * y).mul_add(-(3.0 * y), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:23:13
+   |
+LL |     let _ = x - (y + 1.0 + x).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + x).mul_add(-(y + 1.0 + x), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:24:13
+   |
+LL |     let _ = x - (y + 1.0 + 2.0).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x)`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/fn_null_check.rs b/src/tools/clippy/tests/ui/fn_null_check.rs
new file mode 100644 (file)
index 0000000..df5bc84
--- /dev/null
@@ -0,0 +1,21 @@
+#![allow(unused)]
+#![warn(clippy::fn_null_check)]
+#![allow(clippy::cmp_null)]
+#![allow(clippy::ptr_eq)]
+#![allow(clippy::zero_ptr)]
+
+pub const ZPTR: *const () = 0 as *const _;
+pub const NOT_ZPTR: *const () = 1 as *const _;
+
+fn main() {
+    let fn_ptr = main;
+
+    if (fn_ptr as *mut ()).is_null() {}
+    if (fn_ptr as *const u8).is_null() {}
+    if (fn_ptr as *const ()) == std::ptr::null() {}
+    if (fn_ptr as *const ()) == (0 as *const ()) {}
+    if (fn_ptr as *const ()) == ZPTR {}
+
+    // no lint
+    if (fn_ptr as *const ()) == NOT_ZPTR {}
+}
diff --git a/src/tools/clippy/tests/ui/fn_null_check.stderr b/src/tools/clippy/tests/ui/fn_null_check.stderr
new file mode 100644 (file)
index 0000000..660dd32
--- /dev/null
@@ -0,0 +1,43 @@
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:13:8
+   |
+LL |     if (fn_ptr as *mut ()).is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+   = note: `-D clippy::fn-null-check` implied by `-D warnings`
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:14:8
+   |
+LL |     if (fn_ptr as *const u8).is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:15:8
+   |
+LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:16:8
+   |
+LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:17:8
+   |
+LL |     if (fn_ptr as *const ()) == ZPTR {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: aborting due to 5 previous errors
+
index 3553291b87df6731aca2e71f905ed63eef21cda7..ef6780dc96d9c8f74ec38a3d90767d0b3307710f 100644 (file)
@@ -116,4 +116,45 @@ fn main() {
         },
         None => None,
     };
+
+    match Some(20) {
+        // Don't Lint, because `Some(3*x)` is not `None`
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                Some(3 * x)
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+    let result = if let Some(a) = maybe_some() {
+        if let Some(b) = maybe_some() {
+            Some(a + b)
+        } else {
+            Some(a)
+        }
+    } else {
+        None
+    };
+
+    let allowed_integers = vec![3, 4, 5, 6];
+    // Don't lint, since there's a side effect in the else branch
+    match Some(21) {
+        Some(x) => {
+            if allowed_integers.contains(&x) {
+                Some(x)
+            } else {
+                println!("Invalid integer: {x:?}");
+                None
+            }
+        },
+        None => None,
+    };
+}
+
+fn maybe_some() -> Option<u32> {
+    Some(0)
 }
index aa9f90f752b1790b1cb3ef52d6052d12221503c6..ea0ce83172b7dd4af1469185d0c22f5b68c52717 100644 (file)
@@ -240,4 +240,45 @@ struct NamedTuple {
         },
         None => None,
     };
+
+    match Some(20) {
+        // Don't Lint, because `Some(3*x)` is not `None`
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                Some(3 * x)
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+    let result = if let Some(a) = maybe_some() {
+        if let Some(b) = maybe_some() {
+            Some(a + b)
+        } else {
+            Some(a)
+        }
+    } else {
+        None
+    };
+
+    let allowed_integers = vec![3, 4, 5, 6];
+    // Don't lint, since there's a side effect in the else branch
+    match Some(21) {
+        Some(x) => {
+            if allowed_integers.contains(&x) {
+                Some(x)
+            } else {
+                println!("Invalid integer: {x:?}");
+                None
+            }
+        },
+        None => None,
+    };
+}
+
+fn maybe_some() -> Option<u32> {
+    Some(0)
 }
index e5ae3cf3e5033295b16936b7f71fac65269834f7..8f25fea678f19df58aded7d4add8a5f288e7e32e 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_retain)]
-#![allow(unused)]
+#![allow(unused, clippy::redundant_clone)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
 use std::collections::BinaryHeap;
index 1021f15edd1ea9c579aa8ceff38c17f12eb22414..e6b3995a689b3d077b22da927959d31f59389a9a 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_retain)]
-#![allow(unused)]
+#![allow(unused, clippy::redundant_clone)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
 use std::collections::BinaryHeap;
index a6e315e4773a27907382516d8e37efe5d3d8476b..6cfb6661a03945fc1cfc87691f463aa7fe28ca5b 100644 (file)
@@ -133,3 +133,16 @@ fn issue_9575() {
         println!("Needs curlies");
     };
 }
+
+#[allow(dead_code)]
+fn issue_9725(r: Option<u32>) {
+    let x = r;
+    match x {
+        Some(_) => {
+            println!("Some");
+        },
+        None => {
+            println!("None");
+        },
+    };
+}
index cecbd703e56698cd9292ea24de374cffa03b3e47..f188aeb5f2ff5ce84789643697a816079ea965dd 100644 (file)
@@ -148,3 +148,17 @@ fn side_effects() {}
         _ => println!("Needs curlies"),
     };
 }
+
+#[allow(dead_code)]
+fn issue_9725(r: Option<u32>) {
+    match r {
+        x => match x {
+            Some(_) => {
+                println!("Some");
+            },
+            None => {
+                println!("None");
+            },
+        },
+    };
+}
index 2b9ec7ee7026e4a31f6fdfa7c4f06d06825acde3..e960d64ad2b03dcdbc90ea104535d9d9fa70a5cf 100644 (file)
@@ -213,5 +213,30 @@ LL +         println!("Needs curlies");
 LL ~     };
    |
 
-error: aborting due to 14 previous errors
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:154:5
+   |
+LL | /     match r {
+LL | |         x => match x {
+LL | |             Some(_) => {
+LL | |                 println!("Some");
+...  |
+LL | |         },
+LL | |     };
+   | |_____^
+   |
+help: consider using a `let` statement
+   |
+LL ~     let x = r;
+LL +     match x {
+LL +         Some(_) => {
+LL +             println!("Some");
+LL +         },
+LL +         None => {
+LL +             println!("None");
+LL +         },
+LL ~     };
+   |
+
+error: aborting due to 15 previous errors
 
index e675c183ea7117c646b99e04438c524f07fec3dc..fc252cdd35294dd591f607f133ee0531cbd98788 100644 (file)
@@ -132,3 +132,25 @@ fn main() {
         }
     }
 }
+
+mod issue9993 {
+    enum Foo {
+        A(bool),
+        B,
+    }
+
+    fn test() {
+        let _ = match Foo::A(true) {
+            _ if false => 0,
+            Foo::A(true) => 1,
+            Foo::A(false) => 2,
+            Foo::B => 3,
+        };
+
+        let _ = match Foo::B {
+            _ if false => 0,
+            Foo::A(_) => 1,
+            Foo::B => 2,
+        };
+    }
+}
index 38c3ffc00c71b4bc8cad9251ad1aa4b674899203..9a5c849e6ec9a776c253bbc857edcef8149c5895 100644 (file)
@@ -132,3 +132,25 @@ pub enum Enum {
         }
     }
 }
+
+mod issue9993 {
+    enum Foo {
+        A(bool),
+        B,
+    }
+
+    fn test() {
+        let _ = match Foo::A(true) {
+            _ if false => 0,
+            Foo::A(true) => 1,
+            Foo::A(false) => 2,
+            Foo::B => 3,
+        };
+
+        let _ = match Foo::B {
+            _ if false => 0,
+            Foo::A(_) => 1,
+            _ => 2,
+        };
+    }
+}
index 34538dea8e5f437e836daa4e8aa4bf2dc8074ffd..6fa313dc9111445e6bd402bcad17dd5f1ecc020b 100644 (file)
@@ -48,5 +48,11 @@ error: wildcard matches only a single variant and will also match any future add
 LL |         _ => (),
    |         ^ help: try this: `Color::Blue`
 
-error: aborting due to 8 previous errors
+error: wildcard matches only a single variant and will also match any future added variants
+  --> $DIR/match_wildcard_for_single_variants.rs:153:13
+   |
+LL |             _ => 2,
+   |             ^ help: try this: `Foo::B`
+
+error: aborting due to 9 previous errors
 
index 4cb7f6b687f1195c3bb429b941c8ca256f6534d3..31e1cb6c3d7f7efd0e083c67233079d557f11947 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
@@ -491,3 +491,14 @@ mod issue_9782_method_variant {
         S.foo::<&[u8; 100]>(&a);
     }
 }
+
+extern crate rustc_lint;
+extern crate rustc_span;
+
+#[allow(dead_code)]
+mod span_lint {
+    use rustc_lint::{LateContext, Lint, LintContext};
+    fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
+        cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
+    }
+}
index 9a01190ed8dbd585127276cde688afa19fd07730..55c2738fcf273c812c30105fc84e8090ea4fe927 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
@@ -491,3 +491,14 @@ fn main() {
         S.foo::<&[u8; 100]>(&a);
     }
 }
+
+extern crate rustc_lint;
+extern crate rustc_span;
+
+#[allow(dead_code)]
+mod span_lint {
+    use rustc_lint::{LateContext, Lint, LintContext};
+    fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
+        cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
+    }
+}
index d26c317124b8d18d3dc900d31c8badce92e20af1..98a48d68317b495e9b50713d97aa4d470e2ab4ed 100644 (file)
@@ -216,5 +216,11 @@ error: the borrowed expression implements the required traits
 LL |         foo(&a);
    |             ^^ help: change this to: `a`
 
-error: aborting due to 36 previous errors
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:502:85
+   |
+LL |         cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
+   |                                                                                     ^^^^^^^^^^^^^^ help: change this to: `String::new()`
+
+error: aborting due to 37 previous errors
 
index 4386aaec49e2437751803ac8f9ce216c17e79f07..d451be1f389a7b50a2b3c0201e8ace18d4f0668b 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(lint_reasons)]
+#![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
     clippy::if_same_then_else,
@@ -272,4 +273,8 @@ mod issue9416 {
     }
 }
 
+fn issue9947() -> Result<(), String> {
+    do yeet "hello";
+}
+
 fn main() {}
index 666dc54b76b412b2267e083d3d130929cc07309e..e1a1bea2c0b85f19f769a4c4ea0b904d348f4cf9 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(lint_reasons)]
+#![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
     clippy::if_same_then_else,
@@ -282,4 +283,8 @@ pub fn oneline() {
     }
 }
 
+fn issue9947() -> Result<(), String> {
+    do yeet "hello";
+}
+
 fn main() {}
index a8b5d86cd5581f46a415a3c06f6e2d88cfa0ae60..ca2253e6586379ecb543929782956299a6a08da8 100644 (file)
@@ -1,5 +1,5 @@
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:26:5
+  --> $DIR/needless_return.rs:27:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:30:5
+  --> $DIR/needless_return.rs:31:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:35:9
+  --> $DIR/needless_return.rs:36:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:37:9
+  --> $DIR/needless_return.rs:38:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:43:17
+  --> $DIR/needless_return.rs:44:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:45:13
+  --> $DIR/needless_return.rs:46:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:52:9
+  --> $DIR/needless_return.rs:53:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:54:16
+  --> $DIR/needless_return.rs:55:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:58:5
+  --> $DIR/needless_return.rs:59:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:61:21
+  --> $DIR/needless_return.rs:62:21
    |
 LL |   fn test_void_fun() {
    |  _____________________^
@@ -82,7 +82,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:66:11
+  --> $DIR/needless_return.rs:67:11
    |
 LL |       if b {
    |  ___________^
@@ -92,7 +92,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:68:13
+  --> $DIR/needless_return.rs:69:13
    |
 LL |       } else {
    |  _____________^
@@ -102,7 +102,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:76:14
+  --> $DIR/needless_return.rs:77:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -110,7 +110,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:84:24
+  --> $DIR/needless_return.rs:85:24
    |
 LL |               let _ = 42;
    |  ________________________^
@@ -120,7 +120,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:87:14
+  --> $DIR/needless_return.rs:88:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -128,7 +128,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:100:9
+  --> $DIR/needless_return.rs:101:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:102:9
+  --> $DIR/needless_return.rs:103:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:124:32
+  --> $DIR/needless_return.rs:125:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^
@@ -152,7 +152,7 @@ LL |         bar.unwrap_or_else(|_| return)
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:128:21
+  --> $DIR/needless_return.rs:129:21
    |
 LL |           let _ = || {
    |  _____________________^
@@ -162,7 +162,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:131:20
+  --> $DIR/needless_return.rs:132:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^
@@ -170,7 +170,7 @@ LL |         let _ = || return;
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:137:32
+  --> $DIR/needless_return.rs:138:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^
@@ -178,7 +178,7 @@ LL |         res.unwrap_or_else(|_| return Foo)
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:146:5
+  --> $DIR/needless_return.rs:147:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -186,7 +186,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:150:5
+  --> $DIR/needless_return.rs:151:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -194,7 +194,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:155:9
+  --> $DIR/needless_return.rs:156:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -202,7 +202,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:157:9
+  --> $DIR/needless_return.rs:158:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -210,7 +210,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:163:17
+  --> $DIR/needless_return.rs:164:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -218,7 +218,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:165:13
+  --> $DIR/needless_return.rs:166:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -226,7 +226,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:172:9
+  --> $DIR/needless_return.rs:173:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -234,7 +234,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:174:16
+  --> $DIR/needless_return.rs:175:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -242,7 +242,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:178:5
+  --> $DIR/needless_return.rs:179:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +250,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:181:33
+  --> $DIR/needless_return.rs:182:33
    |
 LL |   async fn async_test_void_fun() {
    |  _________________________________^
@@ -260,7 +260,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:186:11
+  --> $DIR/needless_return.rs:187:11
    |
 LL |       if b {
    |  ___________^
@@ -270,7 +270,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:188:13
+  --> $DIR/needless_return.rs:189:13
    |
 LL |       } else {
    |  _____________^
@@ -280,7 +280,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:196:14
+  --> $DIR/needless_return.rs:197:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -288,7 +288,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:209:9
+  --> $DIR/needless_return.rs:210:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +296,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:211:9
+  --> $DIR/needless_return.rs:212:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +304,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:227:5
+  --> $DIR/needless_return.rs:228:5
    |
 LL |     return format!("Hello {}", "world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +312,7 @@ LL |     return format!("Hello {}", "world!");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:238:9
+  --> $DIR/needless_return.rs:239:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -320,7 +320,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:240:9
+  --> $DIR/needless_return.rs:241:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -328,7 +328,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:247:13
+  --> $DIR/needless_return.rs:248:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -336,7 +336,7 @@ LL |             return 10;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:250:13
+  --> $DIR/needless_return.rs:251:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -344,7 +344,7 @@ LL |             return 100;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:258:9
+  --> $DIR/needless_return.rs:259:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -352,7 +352,7 @@ LL |         return 0;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:265:13
+  --> $DIR/needless_return.rs:266:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +360,7 @@ LL |             return *(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:267:13
+  --> $DIR/needless_return.rs:268:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -368,7 +368,7 @@ LL |             return !*(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:274:20
+  --> $DIR/needless_return.rs:275:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -379,7 +379,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:281:20
+  --> $DIR/needless_return.rs:282:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs b/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs
new file mode 100644 (file)
index 0000000..28c00d1
--- /dev/null
@@ -0,0 +1,29 @@
+#![allow(unused)]
+#![warn(clippy::permissions_set_readonly_false)]
+
+use std::fs::File;
+
+struct A;
+
+impl A {
+    pub fn set_readonly(&mut self, b: bool) {}
+}
+
+fn set_readonly(b: bool) {}
+
+fn main() {
+    let f = File::create("foo.txt").unwrap();
+    let metadata = f.metadata().unwrap();
+    let mut permissions = metadata.permissions();
+    // lint here
+    permissions.set_readonly(false);
+    // no lint
+    permissions.set_readonly(true);
+
+    let mut a = A;
+    // no lint here - a is not of type std::fs::Permissions
+    a.set_readonly(false);
+
+    // no lint here - plain function
+    set_readonly(false);
+}
diff --git a/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr b/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr
new file mode 100644 (file)
index 0000000..e7a8ee6
--- /dev/null
@@ -0,0 +1,13 @@
+error: call to `set_readonly` with argument `false`
+  --> $DIR/permissions_set_readonly_false.rs:19:5
+   |
+LL |     permissions.set_readonly(false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: on Unix platforms this results in the file being world writable
+   = help: you can set the desired permissions using `PermissionsExt`. For more information, see
+           https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html
+   = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings`
+
+error: aborting due to previous error
+
index 00b427450935d5077a7ff947a78da65c5221ef2b..a157b6a6f9adbfd417b10fd0ed51734ab7f63f6f 100644 (file)
@@ -239,3 +239,9 @@ fn false_negative_5707() {
     let _z = x.clone(); // pr 7346 can't lint on `x`
     drop(y);
 }
+
+#[allow(unused, clippy::manual_retain)]
+fn possible_borrower_improvements() {
+    let mut s = String::from("foobar");
+    s = s.chars().filter(|&c| c != 'o').collect();
+}
index f899127db8d04674fab4e5d5282106da2e7721d8..430672e8b8df2ffc470a47146ffd59db0b35fbe6 100644 (file)
@@ -239,3 +239,9 @@ fn foo(_x: &Alpha, _y: &mut Alpha) {}
     let _z = x.clone(); // pr 7346 can't lint on `x`
     drop(y);
 }
+
+#[allow(unused, clippy::manual_retain)]
+fn possible_borrower_improvements() {
+    let mut s = String::from("foobar");
+    s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+}
index 782590034d051cb07c2486e07983958809029a77..1bacc2c76af1597f3b044506ed4e4f081a3b9251 100644 (file)
@@ -179,5 +179,17 @@ note: this value is dropped without further use
 LL |     foo(&x.clone(), move || {
    |          ^
 
-error: aborting due to 15 previous errors
+error: redundant clone
+  --> $DIR/redundant_clone.rs:246:40
+   |
+LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+   |                                        ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:246:9
+   |
+LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
 
index 2e1eb8eb18066796e2eb95c7aa1671ddda5a0e89..d0e534f635682cefd2e12a4f3a390cb3ff7cc3ef 100644 (file)
@@ -19,10 +19,7 @@ LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value)
 error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:29:5
    |
-LL |        x.field.map(|value| {
-   |  ______^
-   | | _____|
-   | ||
+LL | //     x.field.map(|value| {
 LL | ||         do_nothing(value);
 LL | ||         do_nothing(value)
 LL | ||     });
diff --git a/src/tools/clippy/tests/ui/size_of_ref.rs b/src/tools/clippy/tests/ui/size_of_ref.rs
new file mode 100644 (file)
index 0000000..1e83ab8
--- /dev/null
@@ -0,0 +1,27 @@
+#![allow(unused)]
+#![warn(clippy::size_of_ref)]
+
+use std::mem::size_of_val;
+
+fn main() {
+    let x = 5;
+    let y = &x;
+
+    size_of_val(&x); // no lint
+    size_of_val(y); // no lint
+
+    size_of_val(&&x);
+    size_of_val(&y);
+}
+
+struct S {
+    field: u32,
+    data: Vec<u8>,
+}
+
+impl S {
+    /// Get size of object including `self`, in bytes.
+    pub fn size(&self) -> usize {
+        std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/size_of_ref.stderr b/src/tools/clippy/tests/ui/size_of_ref.stderr
new file mode 100644 (file)
index 0000000..d4c13ac
--- /dev/null
@@ -0,0 +1,27 @@
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+  --> $DIR/size_of_ref.rs:13:5
+   |
+LL |     size_of_val(&&x);
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+   = note: `-D clippy::size-of-ref` implied by `-D warnings`
+
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+  --> $DIR/size_of_ref.rs:14:5
+   |
+LL |     size_of_val(&y);
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+  --> $DIR/size_of_ref.rs:25:9
+   |
+LL |         std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
new file mode 100644 (file)
index 0000000..b3ea3d9
--- /dev/null
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+#![warn(clippy::transmute_null_to_fn)]
+#![allow(clippy::zero_ptr)]
+
+// Easy to lint because these only span one line.
+fn one_liners() {
+    unsafe {
+        let _: fn() = std::mem::transmute(0 as *const ());
+        let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+    }
+}
+
+pub const ZPTR: *const usize = 0 as *const _;
+pub const NOT_ZPTR: *const usize = 1 as *const _;
+
+fn transmute_const() {
+    unsafe {
+        // Should raise a lint.
+        let _: fn() = std::mem::transmute(ZPTR);
+        // Should NOT raise a lint.
+        let _: fn() = std::mem::transmute(NOT_ZPTR);
+    }
+}
+
+fn main() {
+    one_liners();
+    transmute_const();
+}
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr
new file mode 100644 (file)
index 0000000..f0c6549
--- /dev/null
@@ -0,0 +1,27 @@
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:8:23
+   |
+LL |         let _: fn() = std::mem::transmute(0 as *const ());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+   = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings`
+
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:9:23
+   |
+LL |         let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:19:23
+   |
+LL |         let _: fn() = std::mem::transmute(ZPTR);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: aborting due to 3 previous errors
+
index 70ff08f36551838743b29d059c5d207a6f1593cd..94b206d8e58f6b4e7c79b29399ae3b670d4cb58f 100644 (file)
@@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
     if Some("ok") == lines.into_iter().next() {}
+}
 
-    Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    if Some("ok") == text.lines().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let _ = NUMBERS.next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let mut n = NUMBERS;
+    n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+    counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+    type Item = u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.counter = self.counter.wrapping_add(1);
+        Some(self.counter)
+    }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+    let mut c = CopiableCounter { counter: 0 };
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.next(), Some(1));
+    assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+    static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+    unsafe {
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.next(), Some(1));
+        assert_eq!(C.next(), Some(2));
+    }
 }
 
 fn main() {
@@ -46,7 +105,15 @@ fn main() {
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
-    test_issue_5833().unwrap();
+
+    dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_expr_implementing_iterator();
+    lint_into_iter_on_expr_implementing_iterator_2();
+    lint_into_iter_on_const_implementing_iterator();
+    lint_into_iter_on_const_implementing_iterator_2();
+    dont_lint_into_iter_on_copy_iter();
+    dont_lint_into_iter_on_static_copy_iter();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
index f2444a8f436bf1a699e45cdee099846a261f9568..c7ae927941bf1cceb72313528ed4f8b539c84f22 100644 (file)
@@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
     if Some("ok") == lines.into_iter().next() {}
+}
 
-    Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.into_iter().next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines().into_iter();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    if Some("ok") == text.lines().into_iter().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let _ = NUMBERS.into_iter().next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let mut n = NUMBERS.into_iter();
+    n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+    counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+    type Item = u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.counter = self.counter.wrapping_add(1);
+        Some(self.counter)
+    }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+    let mut c = CopiableCounter { counter: 0 };
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.next(), Some(1));
+    assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+    static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+    unsafe {
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.next(), Some(1));
+        assert_eq!(C.next(), Some(2));
+    }
 }
 
 fn main() {
@@ -46,7 +105,15 @@ fn main() {
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
-    test_issue_5833().unwrap();
+
+    dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_expr_implementing_iterator();
+    lint_into_iter_on_expr_implementing_iterator_2();
+    lint_into_iter_on_const_implementing_iterator();
+    lint_into_iter_on_const_implementing_iterator_2();
+    dont_lint_into_iter_on_copy_iter();
+    dont_lint_into_iter_on_static_copy_iter();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
index 65ee3807fa9d9b19456730995dec508d1661211c..be067c6843acea3d8c3fd3036346a25be30f571e 100644 (file)
@@ -22,71 +22,101 @@ error: useless conversion to the same type: `i32`
 LL |         let _: i32 = 0i32.into();
    |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:45:22
+   |
+LL |     if Some("ok") == lines.into_iter().next() {}
+   |                      ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:50:21
+   |
+LL |     let mut lines = text.lines().into_iter();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:56:22
+   |
+LL |     if Some("ok") == text.lines().into_iter().next() {}
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+  --> $DIR/useless_conversion.rs:62:13
+   |
+LL |     let _ = NUMBERS.into_iter().next();
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+  --> $DIR/useless_conversion.rs:67:17
+   |
+LL |     let mut n = NUMBERS.into_iter();
+   |                 ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:61:21
+  --> $DIR/useless_conversion.rs:128:21
    |
 LL |     let _: String = "foo".to_string().into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:62:21
+  --> $DIR/useless_conversion.rs:129:21
    |
 LL |     let _: String = From::from("foo".to_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:63:13
+  --> $DIR/useless_conversion.rs:130:13
    |
 LL |     let _ = String::from("foo".to_string());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:64:13
+  --> $DIR/useless_conversion.rs:131:13
    |
 LL |     let _ = String::from(format!("A: {:04}", 123));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:65:13
+  --> $DIR/useless_conversion.rs:132:13
    |
 LL |     let _ = "".lines().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
 
 error: useless conversion to the same type: `std::vec::IntoIter<i32>`
-  --> $DIR/useless_conversion.rs:66:13
+  --> $DIR/useless_conversion.rs:133:13
    |
 LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:67:21
+  --> $DIR/useless_conversion.rs:134:21
    |
 LL |     let _: String = format!("Hello {}", "world").into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 
 error: useless conversion to the same type: `i32`
-  --> $DIR/useless_conversion.rs:72:13
+  --> $DIR/useless_conversion.rs:139:13
    |
 LL |     let _ = i32::from(a + b) * 3;
    |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:78:23
+  --> $DIR/useless_conversion.rs:145:23
    |
 LL |     let _: Foo<'a'> = s2.into();
    |                       ^^^^^^^^^ help: consider removing `.into()`: `s2`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:80:13
+  --> $DIR/useless_conversion.rs:147:13
    |
 LL |     let _ = Foo::<'a'>::from(s3);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
 
 error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
-  --> $DIR/useless_conversion.rs:82:13
+  --> $DIR/useless_conversion.rs:149:13
    |
 LL |     let _ = vec![s4, s4, s4].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 19 previous errors
 
index ef55f1c31a88bef188aba44728b4e9bdda0f890f..0baec6f0b641e7b7297dda743bbcba37c46e4207 100644 (file)
@@ -5,7 +5,6 @@
 // the 2015 edition here is needed because edition 2018 changed the module system
 // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
 // no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
index b81285142069b0e5d14557805ec8211ca5a4cff2..db591d56ab4d17f24e7e16f95518c9201470cad3 100644 (file)
@@ -5,7 +5,6 @@
 // the 2015 edition here is needed because edition 2018 changed the module system
 // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
 // no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
index 626c1754fc82c8720bbc3e1ac84c0f932dbce630..6b469cdfc444926355f72b614ca0787658a95aae 100644 (file)
@@ -1,5 +1,5 @@
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:16:5
+  --> $DIR/wildcard_imports.rs:15:5
    |
 LL | use crate::fn_mod::*;
    |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
@@ -7,85 +7,85 @@ LL | use crate::fn_mod::*;
    = note: `-D clippy::wildcard-imports` implied by `-D warnings`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:17:5
+  --> $DIR/wildcard_imports.rs:16:5
    |
 LL | use crate::mod_mod::*;
    |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:18:5
+  --> $DIR/wildcard_imports.rs:17:5
    |
 LL | use crate::multi_fn_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:20:5
+  --> $DIR/wildcard_imports.rs:19:5
    |
 LL | use crate::struct_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:24:5
+  --> $DIR/wildcard_imports.rs:23:5
    |
 LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:25:5
+  --> $DIR/wildcard_imports.rs:24:5
    |
 LL | use wildcard_imports_helper::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:96:13
+  --> $DIR/wildcard_imports.rs:95:13
    |
 LL |         use crate::fn_mod::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:102:75
+  --> $DIR/wildcard_imports.rs:101:75
    |
 LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
    |                                                                           ^ help: try: `inner_extern_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:103:13
+  --> $DIR/wildcard_imports.rs:102:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:114:20
+  --> $DIR/wildcard_imports.rs:113:20
    |
 LL |         use self::{inner::*, inner2::*};
    |                    ^^^^^^^^ help: try: `inner::inner_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:114:30
+  --> $DIR/wildcard_imports.rs:113:30
    |
 LL |         use self::{inner::*, inner2::*};
    |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:121:13
+  --> $DIR/wildcard_imports.rs:120:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:150:9
+  --> $DIR/wildcard_imports.rs:149:9
    |
 LL |     use crate::in_fn_test::*;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:159:9
+  --> $DIR/wildcard_imports.rs:158:9
    |
 LL |     use crate:: in_fn_test::  * ;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:160:9
+  --> $DIR/wildcard_imports.rs:159:9
    |
 LL |       use crate:: fn_mod::
    |  _________^
@@ -93,37 +93,37 @@ LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:171:13
+  --> $DIR/wildcard_imports.rs:170:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:206:17
+  --> $DIR/wildcard_imports.rs:205:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:214:13
+  --> $DIR/wildcard_imports.rs:213:13
    |
 LL |         use super_imports::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:223:17
+  --> $DIR/wildcard_imports.rs:222:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:232:13
+  --> $DIR/wildcard_imports.rs:231:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:240:13
+  --> $DIR/wildcard_imports.rs:239:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
new file mode 100644 (file)
index 0000000..6d534a1
--- /dev/null
@@ -0,0 +1,240 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
new file mode 100644 (file)
index 0000000..acca9f6
--- /dev/null
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:13:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:14:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:16:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:21:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:91:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:97:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:98:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:116:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:145:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:154:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:155:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:166:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:201:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:209:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:218:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:227:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:235:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
new file mode 100644 (file)
index 0000000..6d534a1
--- /dev/null
@@ -0,0 +1,240 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
new file mode 100644 (file)
index 0000000..acca9f6
--- /dev/null
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:13:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:14:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:16:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:21:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:91:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:97:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:98:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:116:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:145:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:154:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:155:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:166:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:201:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:209:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:218:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:227:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:235:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
new file mode 100644 (file)
index 0000000..b5ed58e
--- /dev/null
@@ -0,0 +1,241 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::*;
+use crate::mod_mod::*;
+use crate::multi_fn_mod::*;
+use crate::struct_mod::*;
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::*;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::*;
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::*;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+        use wildcard_imports_helper::*;
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::*, inner2::*};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::*;
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::*;
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::  * ;
+    use crate:: fn_mod::
+        *;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::*;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::*;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr
new file mode 100644 (file)
index 0000000..92f6d31
--- /dev/null
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:9:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:10:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:11:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:12:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:17:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:87:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:93:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:94:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:105:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:105:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:112:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:141:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:150:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:151:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:162:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:197:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:205:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:214:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:223:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:231:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
index 7a3c0d28fc3e98ee83bdfab1a3fe0b8208e30bea..7e48dd206606867512a6a8e0f4cfcbe122b8317e 100644 (file)
@@ -2011,7 +2011,7 @@ fn make_compile_args(
                 rustc.args(&["-Zpolonius"]);
             }
             Some(CompareMode::Chalk) => {
-                rustc.args(&["-Zchalk"]);
+                rustc.args(&["-Ztrait-solver=chalk"]);
             }
             Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
                 rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
index ccba313ee357bf10c387f58cc99a8f5c6e5ceca2..6c63b760ff6a9de167c26c783851beee3dbc2981 100644 (file)
@@ -11,7 +11,7 @@
 
 pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
-    "aarch64-fuchsia",
+    "aarch64-unknown-fuchsia",
     "aarch64-linux-android",
     "aarch64-unknown-linux-gnu",
     "arm-linux-androideabi",
@@ -19,7 +19,7 @@
     "i686-linux-android",
     "i686-unknown-linux-gnu",
     "x86_64-apple-darwin",
-    "x86_64-fuchsia",
+    "x86_64-unknown-fuchsia",
     "x86_64-linux-android",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-linux-gnu",
 // FIXME(rcvalle): More targets are likely supported.
 pub const CFI_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
-    "aarch64-fuchsia",
+    "aarch64-unknown-fuchsia",
     "aarch64-linux-android",
     "aarch64-unknown-freebsd",
     "aarch64-unknown-linux-gnu",
     "x86_64-apple-darwin",
-    "x86_64-fuchsia",
+    "x86_64-unknown-fuchsia",
     "x86_64-pc-solaris",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-illumos",
index 885100ae3a4490fe63075580c60b29118ee310d3..2701ad917bb0954febe9554c1a0db24d85663a47 100644 (file)
@@ -7,6 +7,7 @@ src = ""
 git-repository-url = "https://github.com/rust-lang/rust/"
 additional-css = ["error-index.css"]
 additional-js = ["error-index.js"]
+input-404 = ""
 
 [output.html.search]
 enable = true
index 1bde8e007826dffca053aa69474ecba3530ea68a..98eda97e236cbf3642a85da5551e79ef1cd980d4 100644 (file)
@@ -98,8 +98,7 @@ fn add_rust_attribute_on_codeblock(explanation: &str) -> String {
 
 fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
     let mut introduction = format!(
-        "<script src='redirect.js'></script>
-# Rust error codes index
+        "# Rust error codes index
 
 This page lists all the error codes emitted by the Rust compiler.
 
@@ -149,7 +148,12 @@ fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
     book.book.sections.push(BookItem::Chapter(chapter));
     book.build()?;
 
-    // We can't put this content into another file, otherwise `mbdbook` will also put it into the
+    // The error-index used to be generated manually (without mdbook), and the
+    // index was located at the top level. Now that it is generated with
+    // mdbook, error-index.html has moved to error_codes/error-index.html.
+    // This adds a redirect so that old links go to the new location.
+    //
+    // We can't put this content into another file, otherwise `mdbook` will also put it into the
     // output directory, making a duplicate.
     fs::write(
         output_path.join("error-index.html"),
@@ -163,14 +167,10 @@ fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
     </head>
     <body>
         <div>If you are not automatically redirected to the error code index, please <a id="index-link" href="./error_codes/error-index.html">here</a>.
-        <script>document.getElementById("index-link").click()</script>
     </body>
 </html>"#,
     )?;
 
-    // No need for a 404 file, it's already handled by the server.
-    fs::remove_file(output_path.join("error_codes/404.html"))?;
-
     Ok(())
 }
 
index 8c907f5795d324be867a792e25aeac775ebd3b88..c80cbf297afffeab665939ebfd2491e21ceace1c 100644 (file)
@@ -3,14 +3,10 @@
         let code = window.location.hash.replace(/^#/, '');
         // We have to make sure this pattern matches to avoid inadvertently creating an
         // open redirect.
-        if (!/^E[0-9]+$/.test(code)) {
+        if (/^E[0-9]+$/.test(code)) {
+            window.location.replace('./error_codes/' + code + '.html');
             return;
         }
-        if (window.location.pathname.indexOf("/error_codes/") !== -1) {
-            // We're not at the top level, so we don't prepend with "./error_codes/".
-            window.location = './' + code + '.html';
-        } else {
-            window.location = './error_codes/' + code + '.html';
-        }
     }
+    window.location.replace('./error_codes/error-index.html');
 })()
index 84a6c7f96c4644631e66c51070b9c4720af472f8..8990310a4f474073ad3233a3d5d99773c21c4458 100644 (file)
@@ -7,6 +7,8 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.62"
+clap = { version = "4.0.15", features = ["derive"] }
 fs-err = "2.8.1"
 rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" }
+serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.85"
index 70e7440f73085e67ee8d91df7bcb9188007f0efc..a183c4068ce85af48f175517fbd9ae56896ef1f2 100644 (file)
@@ -1,8 +1,9 @@
 use std::fmt::Write;
 
+use serde::Serialize;
 use serde_json::Value;
 
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 pub enum SelectorPart {
     Field(String),
     Index(usize),
index fc54c421b4b22962417296c2a1a9951196bcc604..05e938f4f7df4f906afcb73ac7cdb757c8c33c10 100644 (file)
-use std::env;
+use std::io::{BufWriter, Write};
 
-use anyhow::{anyhow, bail, Result};
+use anyhow::{bail, Result};
+use clap::Parser;
 use fs_err as fs;
 use rustdoc_json_types::{Crate, Id, FORMAT_VERSION};
+use serde::Serialize;
 use serde_json::Value;
 
 pub(crate) mod item_kind;
 mod json_find;
 mod validator;
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
 struct Error {
     kind: ErrorKind,
     id: Id,
 }
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
 enum ErrorKind {
-    NotFound,
+    NotFound(Vec<json_find::Selector>),
     Custom(String),
 }
 
+#[derive(Debug, Serialize)]
+struct JsonOutput {
+    path: String,
+    errors: Vec<Error>,
+}
+
+#[derive(Parser)]
+struct Cli {
+    /// The path to the json file to be linted
+    path: String,
+
+    /// Show verbose output
+    #[arg(long)]
+    verbose: bool,
+
+    #[arg(long)]
+    json_output: Option<String>,
+}
+
 fn main() -> Result<()> {
-    let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?;
+    let Cli { path, verbose, json_output } = Cli::parse();
+
     let contents = fs::read_to_string(&path)?;
     let krate: Crate = serde_json::from_str(&contents)?;
     assert_eq!(krate.format_version, FORMAT_VERSION);
 
-    let mut validator = validator::Validator::new(&krate);
+    let krate_json: Value = serde_json::from_str(&contents)?;
+
+    let mut validator = validator::Validator::new(&krate, krate_json);
     validator.check_crate();
 
+    if let Some(json_output) = json_output {
+        let output = JsonOutput { path: path.clone(), errors: validator.errs.clone() };
+        let mut f = BufWriter::new(fs::File::create(json_output)?);
+        serde_json::to_writer(&mut f, &output)?;
+        f.flush()?;
+    }
+
     if !validator.errs.is_empty() {
         for err in validator.errs {
             match err.kind {
-                ErrorKind::NotFound => {
-                    let krate_json: Value = serde_json::from_str(&contents)?;
-
-                    let sels =
-                        json_find::find_selector(&krate_json, &Value::String(err.id.0.clone()));
-                    match &sels[..] {
-                        [] => unreachable!(
-                            "id must be in crate, or it wouldn't be reported as not found"
-                        ),
-                        [sel] => eprintln!(
-                            "{} not in index or paths, but refered to at '{}'",
-                            err.id.0,
-                            json_find::to_jsonpath(&sel)
-                        ),
-                        [sel, ..] => eprintln!(
-                            "{} not in index or paths, but refered to at '{}' and more",
-                            err.id.0,
-                            json_find::to_jsonpath(&sel)
-                        ),
+                ErrorKind::NotFound(sels) => match &sels[..] {
+                    [] => {
+                        unreachable!(
+                            "id {:?} must be in crate, or it wouldn't be reported as not found",
+                            err.id
+                        )
+                    }
+                    [sel] => eprintln!(
+                        "{} not in index or paths, but refered to at '{}'",
+                        err.id.0,
+                        json_find::to_jsonpath(&sel)
+                    ),
+                    [sel, ..] => {
+                        if verbose {
+                            let sels = sels
+                                .iter()
+                                .map(json_find::to_jsonpath)
+                                .map(|i| format!("'{i}'"))
+                                .collect::<Vec<_>>()
+                                .join(", ");
+                            eprintln!(
+                                "{} not in index or paths, but refered to at {sels}",
+                                err.id.0
+                            );
+                        } else {
+                            eprintln!(
+                                "{} not in index or paths, but refered to at '{}' and {} more",
+                                err.id.0,
+                                json_find::to_jsonpath(&sel),
+                                sels.len() - 1,
+                            )
+                        }
                     }
-                }
+                },
                 ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
             }
         }
index e15f5fe3ccc968d46d295534015c3831d0ebff85..c6f55410e44377fb846adc3479fafbc4c4cff61e 100644 (file)
@@ -3,12 +3,16 @@
 
 use rustdoc_json_types::{
     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
-    GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
-    Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
-    TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+    GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module,
+    OpaqueTy, Path, Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias,
+    Type, TypeBinding, TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
 };
+use serde_json::Value;
 
-use crate::{item_kind::Kind, Error, ErrorKind};
+use crate::{item_kind::Kind, json_find, Error, ErrorKind};
+
+// This is a rustc implementation detail that we rely on here
+const LOCAL_CRATE_ID: u32 = 0;
 
 /// The Validator walks over the JSON tree, and ensures it is well formed.
 /// It is made of several parts.
@@ -22,6 +26,7 @@
 pub struct Validator<'a> {
     pub(crate) errs: Vec<Error>,
     krate: &'a Crate,
+    krate_json: Value,
     /// Worklist of Ids to check.
     todo: HashSet<&'a Id>,
     /// Ids that have already been visited, so don't need to be checked again.
@@ -39,9 +44,10 @@ enum PathKind {
 }
 
 impl<'a> Validator<'a> {
-    pub fn new(krate: &'a Crate) -> Self {
+    pub fn new(krate: &'a Crate, krate_json: Value) -> Self {
         Self {
             krate,
+            krate_json,
             errs: Vec::new(),
             seen_ids: HashSet::new(),
             todo: HashSet::new(),
@@ -50,12 +56,19 @@ pub fn new(krate: &'a Crate) -> Self {
     }
 
     pub fn check_crate(&mut self) {
+        // Graph traverse the index
         let root = &self.krate.root;
         self.add_mod_id(root);
         while let Some(id) = set_remove(&mut self.todo) {
             self.seen_ids.insert(id);
             self.check_item(id);
         }
+
+        let root_crate_id = self.krate.index[root].crate_id;
+        assert_eq!(root_crate_id, LOCAL_CRATE_ID, "LOCAL_CRATE_ID is wrong");
+        for (id, item_info) in &self.krate.paths {
+            self.check_item_info(id, item_info);
+        }
     }
 
     fn check_item(&mut self, id: &'a Id) {
@@ -140,24 +153,24 @@ fn check_enum(&mut self, x: &'a Enum) {
     }
 
     fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
-        match x {
-            Variant::Plain(discr) => {
-                if let Some(discr) = discr {
-                    if let (Err(_), Err(_)) =
-                        (discr.value.parse::<i128>(), discr.value.parse::<u128>())
-                    {
-                        self.fail(
-                            id,
-                            ErrorKind::Custom(format!(
-                                "Failed to parse discriminant value `{}`",
-                                discr.value
-                            )),
-                        );
-                    }
-                }
+        let Variant { kind, discriminant } = x;
+
+        if let Some(discr) = discriminant {
+            if let (Err(_), Err(_)) = (discr.value.parse::<i128>(), discr.value.parse::<u128>()) {
+                self.fail(
+                    id,
+                    ErrorKind::Custom(format!(
+                        "Failed to parse discriminant value `{}`",
+                        discr.value
+                    )),
+                );
             }
-            Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
-            Variant::Struct { fields, fields_stripped: _ } => {
+        }
+
+        match kind {
+            VariantKind::Plain => {}
+            VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+            VariantKind::Struct { fields, fields_stripped: _ } => {
                 fields.iter().for_each(|f| self.add_field_id(f))
             }
         }
@@ -361,6 +374,19 @@ fn check_function_pointer(&mut self, fp: &'a FunctionPointer) {
         fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
     }
 
+    fn check_item_info(&mut self, id: &Id, item_info: &ItemSummary) {
+        // FIXME: Their should be a better way to determine if an item is local, rather than relying on `LOCAL_CRATE_ID`,
+        // which encodes rustc implementation details.
+        if item_info.crate_id == LOCAL_CRATE_ID && !self.krate.index.contains_key(id) {
+            self.errs.push(Error {
+                id: id.clone(),
+                kind: ErrorKind::Custom(
+                    "Id for local item in `paths` but not in `index`".to_owned(),
+                ),
+            })
+        }
+    }
+
     fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) {
         if let Some(kind) = self.kind_of(id) {
             if valid(kind) {
@@ -373,7 +399,11 @@ fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str
         } else {
             if !self.missing_ids.contains(id) {
                 self.missing_ids.insert(id);
-                self.fail(id, ErrorKind::NotFound)
+
+                let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone()));
+                assert_ne!(sels.len(), 0);
+
+                self.fail(id, ErrorKind::NotFound(sels))
             }
         }
     }
index c4aeee9c53b760162af70925c189148d2fed723c..1ef41ff123abf68eaad360096c10f2d69f13a4b4 100644 (file)
@@ -1,12 +1,17 @@
 use std::collections::HashMap;
 
-use rustdoc_json_types::{Crate, Item, Visibility};
+use rustdoc_json_types::{Crate, Item, ItemKind, ItemSummary, Visibility, FORMAT_VERSION};
+
+use crate::json_find::SelectorPart;
 
 use super::*;
 
 #[track_caller]
 fn check(krate: &Crate, errs: &[Error]) {
-    let mut validator = Validator::new(krate);
+    let krate_string = serde_json::to_string(krate).unwrap();
+    let krate_json = serde_json::from_str(&krate_string).unwrap();
+
+    let mut validator = Validator::new(krate, krate_json);
     validator.check_crate();
 
     assert_eq!(errs, &validator.errs[..]);
@@ -46,5 +51,114 @@ fn errors_on_missing_links() {
         format_version: rustdoc_json_types::FORMAT_VERSION,
     };
 
-    check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]);
+    check(
+        &k,
+        &[Error {
+            kind: ErrorKind::NotFound(vec![vec![
+                SelectorPart::Field("index".to_owned()),
+                SelectorPart::Field("0".to_owned()),
+                SelectorPart::Field("links".to_owned()),
+                SelectorPart::Field("Not Found".to_owned()),
+            ]]),
+            id: id("1"),
+        }],
+    );
+}
+
+// Test we would catch
+// https://github.com/rust-lang/rust/issues/104064#issuecomment-1368589718
+#[test]
+fn errors_on_local_in_paths_and_not_index() {
+    let krate = Crate {
+        root: id("0:0:1572"),
+        crate_version: None,
+        includes_private: false,
+        index: HashMap::from_iter([
+            (
+                id("0:0:1572"),
+                Item {
+                    id: id("0:0:1572"),
+                    crate_id: 0,
+                    name: Some("microcore".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: HashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Module(Module {
+                        is_crate: true,
+                        items: vec![id("0:1:717")],
+                        is_stripped: false,
+                    }),
+                },
+            ),
+            (
+                id("0:1:717"),
+                Item {
+                    id: id("0:1:717"),
+                    crate_id: 0,
+                    name: Some("i32".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: HashMap::default(),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
+                },
+            ),
+        ]),
+        paths: HashMap::from_iter([(
+            id("0:1:1571"),
+            ItemSummary {
+                crate_id: 0,
+                path: vec!["microcore".to_owned(), "i32".to_owned()],
+                kind: ItemKind::Primitive,
+            },
+        )]),
+        external_crates: HashMap::default(),
+        format_version: rustdoc_json_types::FORMAT_VERSION,
+    };
+
+    check(
+        &krate,
+        &[Error {
+            id: id("0:1:1571"),
+            kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()),
+        }],
+    );
+}
+
+#[test]
+#[should_panic = "LOCAL_CRATE_ID is wrong"]
+fn checks_local_crate_id_is_correct() {
+    let krate = Crate {
+        root: id("root"),
+        crate_version: None,
+        includes_private: false,
+        index: HashMap::from_iter([(
+            id("root"),
+            Item {
+                id: id("root"),
+                crate_id: LOCAL_CRATE_ID.wrapping_add(1),
+                name: Some("irrelavent".to_owned()),
+                span: None,
+                visibility: Visibility::Public,
+                docs: None,
+                links: HashMap::default(),
+                attrs: Vec::new(),
+                deprecation: None,
+                inner: ItemEnum::Module(Module {
+                    is_crate: true,
+                    items: vec![],
+                    is_stripped: false,
+                }),
+            },
+        )]),
+        paths: HashMap::default(),
+        external_crates: HashMap::default(),
+        format_version: FORMAT_VERSION,
+    };
+    check(&krate, &[]);
 }
index 876d49257caa5beb283092fddea261457706a970..d17bb9533b438a6d13853dcd1b6985b53dc1d79b 100644 (file)
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.17.0"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
 dependencies = [
  "gimli",
 ]
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aho-corasick"
-version = "0.7.19"
+version = "0.7.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
 dependencies = [
  "memchr",
 ]
@@ -45,9 +45,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.66"
+version = "0.3.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
 dependencies = [
  "addr2line",
  "cc",
@@ -66,9 +66,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bstr"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
+checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b"
 dependencies = [
  "memchr",
  "once_cell",
@@ -96,22 +96,23 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.15.0"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
+checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a"
 dependencies = [
  "camino",
  "cargo-platform",
  "semver",
  "serde",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
 name = "cc"
-version = "1.0.73"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
 
 [[package]]
 name = "cfg-if"
@@ -169,12 +170,11 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.11"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
 dependencies = [
  "cfg-if",
- "once_cell",
 ]
 
 [[package]]
@@ -185,9 +185,9 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
 
 [[package]]
 name = "env_logger"
-version = "0.9.1"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
 dependencies = [
  "atty",
  "humantime",
@@ -217,9 +217,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
  "libc",
@@ -228,9 +228,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.26.2"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
 
 [[package]]
 name = "hermit-abi"
@@ -264,9 +264,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.3"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
 
 [[package]]
 name = "lazy_static"
@@ -276,9 +276,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.133"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 
 [[package]]
 name = "libffi"
@@ -301,9 +301,9 @@ dependencies = [
 
 [[package]]
 name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
 dependencies = [
  "cfg-if",
  "winapi",
@@ -359,9 +359,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.5.4"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
 dependencies = [
  "adler",
 ]
@@ -389,18 +389,18 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.29.0"
+version = "0.30.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.15.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "owo-colors"
@@ -421,9 +421,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.8.5"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
 dependencies = [
  "cfg-if",
  "instant",
@@ -450,24 +450,24 @@ checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.45"
+version = "1.0.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3edcd08cf4fea98d1ae6c9ddd3b8ccb1acac7c3693d62625969a7daa04a2ae36"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.21"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
 dependencies = [
  "proc-macro2",
 ]
@@ -513,9 +513,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -530,9 +530,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.27"
+version = "0.6.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
 
 [[package]]
 name = "remove_dir_all"
@@ -572,9 +572,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
 
 [[package]]
 name = "scopeguard"
@@ -584,27 +584,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "semver"
-version = "1.0.14"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
+checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.145"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.145"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -613,9 +613,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
 dependencies = [
  "itoa",
  "ryu",
@@ -633,15 +633,15 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
 
 [[package]]
 name = "syn"
-version = "1.0.101"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -671,6 +671,26 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "thiserror"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "thread_local"
 version = "1.1.4"
@@ -682,9 +702,9 @@ dependencies = [
 
 [[package]]
 name = "tracing"
-version = "0.1.36"
+version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
 dependencies = [
  "cfg-if",
  "pin-project-lite",
@@ -693,9 +713,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.29"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
+checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
 dependencies = [
  "once_cell",
  "valuable",
@@ -713,9 +733,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.15"
+version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
+checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
 dependencies = [
  "sharded-slab",
  "thread_local",
@@ -744,9 +764,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
 
 [[package]]
 name = "valuable"
index 3e5d388668b3e64130fea4c5700026dc2ab8cf27..37926db0166b71b88961be3a28b3043ef72ae868 100644 (file)
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "anyhow"
-version = "1.0.65"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
+checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
 
 [[package]]
 name = "bitflags"
@@ -48,15 +48,16 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.15.0"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
+checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a"
 dependencies = [
  "camino",
  "cargo-platform",
  "semver",
  "serde",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
@@ -96,9 +97,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
  "libc",
@@ -116,30 +117,30 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.3"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
 
 [[package]]
 name = "libc"
-version = "0.2.133"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.45"
+version = "1.0.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3edcd08cf4fea98d1ae6c9ddd3b8ccb1acac7c3693d62625969a7daa04a2ae36"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.21"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
 dependencies = [
  "proc-macro2",
 ]
@@ -175,9 +176,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20c4b4625eeb148cccf82d5e9b90ad7fab3b11a0204cf75cc7fa04981a0fdffd"
+checksum = "d65b1271cdac365b71b59570ea35d945dea2dd2cc47eba3d33b4bd1e0190ac6d"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -207,33 +208,33 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
 
 [[package]]
 name = "semver"
-version = "1.0.14"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
+checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.145"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.145"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -242,9 +243,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
 dependencies = [
  "itoa",
  "ryu",
@@ -253,9 +254,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.101"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -278,18 +279,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.37"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.37"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -298,9 +299,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
 
 [[package]]
 name = "wasi"
index ce8457469e7cf029887514a193b9691961ddc777..2197160bc9d441e93dc370c1f361c249e94412ed 100644 (file)
@@ -18,7 +18,7 @@ directories = "4"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.15.0"
-rustc-build-sysroot = "0.4"
+rustc-build-sysroot = "0.4.1"
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
 # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
index 2bffff47722704d7b863b4a5aa6ea7ec0024a6c5..e51bfa3798f3ecdd0b6a4ed9abf06bc8a8024366 100644 (file)
@@ -236,22 +236,36 @@ fn is_runnable_crate() -> bool {
         is_bin || is_test
     }
 
-    fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
-        if let Some(out_dir) = get_arg_flag_value("--out-dir") {
-            let mut path = PathBuf::from(out_dir);
-            path.push(format!(
-                "{}{}{}{}",
-                prefix,
-                get_arg_flag_value("--crate-name").unwrap(),
-                // This is technically a `-C` flag but the prefix seems unique enough...
-                // (and cargo passes this before the filename so it should be unique)
-                get_arg_flag_value("extra-filename").unwrap_or_default(),
-                suffix,
-            ));
-            path
+    fn out_filenames() -> Vec<PathBuf> {
+        if let Some(out_file) = get_arg_flag_value("-o") {
+            // `-o` has precedence over `--out-dir`.
+            vec![PathBuf::from(out_file)]
         } else {
-            let out_file = get_arg_flag_value("-o").unwrap();
-            PathBuf::from(out_file)
+            let out_dir = get_arg_flag_value("--out-dir").unwrap_or_default();
+            let path = PathBuf::from(out_dir);
+            // Ask rustc for the filename (since that is target-dependent).
+            let mut rustc = miri_for_host(); // sysroot doesn't matter for this so we just use the host
+            rustc.arg("--print").arg("file-names");
+            for flag in ["--crate-name", "--crate-type", "--target"] {
+                for val in get_arg_flag_values(flag) {
+                    rustc.arg(flag).arg(val);
+                }
+            }
+            // This is technically passed as `-C extra-filename=...`, but the prefix seems unique
+            // enough... (and cargo passes this before the filename so it should be unique)
+            if let Some(extra) = get_arg_flag_value("extra-filename") {
+                rustc.arg("-C").arg(format!("extra-filename={extra}"));
+            }
+            rustc.arg("-");
+
+            let output = rustc.output().expect("cannot run rustc to determine file name");
+            assert!(
+                output.status.success(),
+                "rustc failed when determining file name:\n{output:?}"
+            );
+            let output =
+                String::from_utf8(output.stdout).expect("rustc returned non-UTF-8 filename");
+            output.lines().filter(|l| !l.is_empty()).map(|l| path.join(l)).collect()
         }
     }
 
@@ -267,24 +281,28 @@ fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
     let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
 
     let store_json = |info: CrateRunInfo| {
-        // Create a stub .d file to stop Cargo from "rebuilding" the crate:
-        // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693
-        // As we store a JSON file instead of building the crate here, an empty file is fine.
-        let dep_info_name = out_filename("", ".d");
-        if verbose > 0 {
-            eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display());
+        if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") {
+            // Create a stub .d file to stop Cargo from "rebuilding" the crate:
+            // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693
+            // As we store a JSON file instead of building the crate here, an empty file is fine.
+            let dep_info_name = format!(
+                "{}/{}{}.d",
+                get_arg_flag_value("--out-dir").unwrap(),
+                get_arg_flag_value("--crate-name").unwrap(),
+                get_arg_flag_value("extra-filename").unwrap_or_default(),
+            );
+            if verbose > 0 {
+                eprintln!("[cargo-miri rustc] writing stub dep-info to `{dep_info_name}`");
+            }
+            File::create(dep_info_name).expect("failed to create fake .d file");
         }
-        File::create(dep_info_name).expect("failed to create fake .d file");
 
-        let filename = out_filename("", "");
-        if verbose > 0 {
-            eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display());
+        for filename in out_filenames() {
+            if verbose > 0 {
+                eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display());
+            }
+            info.store(&filename);
         }
-        info.store(&filename);
-        // For Windows and WASM, do the same thing again with `.exe`/`.wasm` appended to the filename.
-        // (Need to do this here as cargo moves that "binary" to a different place before running it.)
-        info.store(&out_filename("", ".exe"));
-        info.store(&out_filename("", ".wasm"));
     };
 
     let runnable_crate = !info_query && is_runnable_crate();
@@ -323,11 +341,14 @@ fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
 
             // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above.
             let mut args = env.args;
+            let mut out_filename = None;
             for i in 0..args.len() {
                 if args[i] == "-o" {
+                    out_filename = Some(args[i + 1].clone());
                     args[i + 1].push_str(".miri");
                 }
             }
+            let out_filename = out_filename.expect("rustdoc must pass `-o`");
 
             cmd.args(&args);
             cmd.env("MIRI_BE_RUSTC", "target");
@@ -340,7 +361,7 @@ fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
                 eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{cmd:?}");
             }
 
-            exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display()));
+            exec_with_pipe(cmd, &env.stdin, format!("{out_filename}.stdin"));
         }
 
         return;
@@ -422,15 +443,12 @@ fn out_filename(prefix: &str, suffix: &str) -> PathBuf {
     // Create a stub .rlib file if "link" was requested by cargo.
     // This is necessary to prevent cargo from doing rebuilds all the time.
     if emit_link_hack {
-        // Some platforms prepend "lib", some do not... let's just create both files.
-        File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file");
-        File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file");
-        // Just in case this is a cdylib or staticlib, also create those fake files.
-        File::create(out_filename("lib", ".so")).expect("failed to create fake .so file");
-        File::create(out_filename("lib", ".a")).expect("failed to create fake .a file");
-        File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file");
-        File::create(out_filename("", ".dll")).expect("failed to create fake .dll file");
-        File::create(out_filename("", ".lib")).expect("failed to create fake .lib file");
+        for filename in out_filenames() {
+            if verbose > 0 {
+                eprintln!("[cargo-miri rustc] creating fake lib file at `{}`", filename.display());
+            }
+            File::create(filename).expect("failed to create fake lib file");
+        }
     }
 
     debug_cmd("[cargo-miri rustc]", verbose, &cmd);
index a696546954f90b9b3450aeb4610784cd1139742d..2e4f0a71013c06b9fa64b1ea01963d742fa5a3d9 100644 (file)
@@ -137,9 +137,11 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
         .rustflags(rustflags)
         .cargo(cargo_cmd)
         .build_from_source(&rust_src)
-        .unwrap_or_else(|_| {
-            if only_setup {
-                show_error!("failed to build sysroot, see error details above")
+        .unwrap_or_else(|err| {
+            if print_sysroot {
+                show_error!("failed to build sysroot")
+            } else if only_setup {
+                show_error!("failed to build sysroot: {err:?}")
             } else {
                 show_error!(
                     "failed to build sysroot; run `cargo miri setup` to see the error details"
index e455b482338f4b7d4cd748b1bfa8f34f799e5ead..b35f7370d68a57743803d427aa2cd5e7841cdd29 100755 (executable)
@@ -108,8 +108,9 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
     MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
-    MIRI_TEST_TARGET=wasm32-wasi MIRI_NO_STD=1 run_tests_minimal no_std # supports std but miri doesn't support it
+    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer
     MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
+    MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
     ;;
   x86_64-apple-darwin)
     MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture
index 97750cb78cdcb9ae19fea8ce13521c081aa3c519..7024927b20561e81f78a432107f579afa683474c 100644 (file)
 extern crate rustc_span;
 extern crate rustc_target;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 mod borrow_tracker;
 mod clock;
 mod concurrency;
index 4321bdf9aae67e5f18b4044d7f58e0a7acd797dd..c792a27ab4ca29b93f5a0d0ce9961a3589d696be 100644 (file)
@@ -47,7 +47,7 @@ fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
         let min_align = match this.tcx.sess.target.arch.as_ref() {
             "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
             "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16,
-            arch => bug!("Unsupported target architecture: {}", arch),
+            arch => bug!("unsupported target architecture for malloc: `{}`", arch),
         };
         // Windows always aligns, even small allocations.
         // Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
@@ -320,7 +320,10 @@ fn emulate_foreign_item(
                     return Ok(Some(body));
                 }
 
-                this.handle_unsupported(format!("can't call foreign function: {link_name}"))?;
+                this.handle_unsupported(format!(
+                    "can't call foreign function `{link_name}` on OS `{os}`",
+                    os = this.tcx.sess.target.os,
+                ))?;
                 return Ok(None);
             }
         }
@@ -336,9 +339,7 @@ fn emulate_allocator(
     ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
         let this = self.eval_context_mut();
 
-        let allocator_kind = if let Some(allocator_kind) = this.tcx.allocator_kind(()) {
-            allocator_kind
-        } else {
+        let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
             // in real code, this symbol does not exist without an allocator
             return Ok(EmulateByNameResult::NotSupported);
         };
@@ -420,9 +421,9 @@ fn emulate_foreign_item_by_name(
                 let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
-                    err_machine_stop!(TerminationInfo::Abort(
-                        format!("pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}")
-                    ))
+                    err_machine_stop!(TerminationInfo::Abort(format!(
+                        "pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}"
+                    )))
                 })?;
                 this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
             }
@@ -438,7 +439,9 @@ fn emulate_foreign_item_by_name(
                 let ptr = this.read_pointer(ptr)?;
                 let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?;
                 if offset != Size::ZERO {
-                    throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block");
+                    throw_unsup_format!(
+                        "pointer passed to miri_static_root must point to beginning of an allocated block"
+                    );
                 }
                 this.machine.static_roots.push(alloc_id);
             }
@@ -453,7 +456,8 @@ fn emulate_foreign_item_by_name(
 
                 // We read this as a plain OsStr and write it as a path, which will convert it to the target.
                 let path = this.read_os_str_from_c_str(ptr)?.to_owned();
-                let (success, needed_size) = this.write_path_to_c_str(Path::new(&path), out, out_size)?;
+                let (success, needed_size) =
+                    this.write_path_to_c_str(Path::new(&path), out, out_size)?;
                 // Return value: 0 on success, otherwise the size it would have needed.
                 this.write_int(if success { 0 } else { needed_size }, dest)?;
             }
@@ -505,11 +509,13 @@ fn emulate_foreign_item_by_name(
                 this.write_pointer(res, dest)?;
             }
             "calloc" => {
-                let [items, len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let [items, len] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let items = this.read_machine_usize(items)?;
                 let len = this.read_machine_usize(len)?;
-                let size =
-                    items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
+                let size = items
+                    .checked_mul(len)
+                    .ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
                 let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?;
                 this.write_pointer(res, dest)?;
             }
@@ -519,7 +525,8 @@ fn emulate_foreign_item_by_name(
                 this.free(ptr, MiriMemoryKind::C)?;
             }
             "realloc" => {
-                let [old_ptr, new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let [old_ptr, new_size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let old_ptr = this.read_pointer(old_ptr)?;
                 let new_size = this.read_machine_usize(new_size)?;
                 let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?;
@@ -551,11 +558,12 @@ fn emulate_foreign_item_by_name(
                 };
 
                 match link_name.as_str() {
-                    "__rust_alloc" => return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
+                    "__rust_alloc" =>
+                        return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
                     "miri_alloc" => {
                         default(this)?;
                         return Ok(EmulateByNameResult::NeedsJumping);
-                    },
+                    }
                     _ => unreachable!(),
                 }
             }
@@ -574,7 +582,11 @@ fn emulate_foreign_item_by_name(
                     )?;
 
                     // We just allocated this, the access is definitely in-bounds.
-                    this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap();
+                    this.write_bytes_ptr(
+                        ptr.into(),
+                        iter::repeat(0u8).take(usize::try_from(size).unwrap()),
+                    )
+                    .unwrap();
                     this.write_pointer(ptr, dest)
                 });
             }
@@ -600,7 +612,8 @@ fn emulate_foreign_item_by_name(
                 };
 
                 match link_name.as_str() {
-                    "__rust_dealloc" => return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
+                    "__rust_dealloc" =>
+                        return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
                     "miri_dealloc" => {
                         default(this)?;
                         return Ok(EmulateByNameResult::NeedsJumping);
@@ -609,7 +622,8 @@ fn emulate_foreign_item_by_name(
                 }
             }
             "__rust_realloc" => {
-                let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+                let [ptr, old_size, align, new_size] =
+                    this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let old_size = this.read_machine_usize(old_size)?;
                 let align = this.read_machine_usize(align)?;
@@ -633,7 +647,8 @@ fn emulate_foreign_item_by_name(
 
             // C memory handling functions
             "memcmp" => {
-                let [left, right, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let [left, right, n] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let left = this.read_pointer(left)?;
                 let right = this.read_pointer(right)?;
                 let n = Size::from_bytes(this.read_machine_usize(n)?);
@@ -653,7 +668,8 @@ fn emulate_foreign_item_by_name(
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
             "memrchr" => {
-                let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let [ptr, val, num] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_machine_usize(num)?;
@@ -676,7 +692,8 @@ fn emulate_foreign_item_by_name(
                 }
             }
             "memchr" => {
-                let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let [ptr, val, num] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_machine_usize(num)?;
@@ -699,7 +716,10 @@ fn emulate_foreign_item_by_name(
                 let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let n = this.read_c_str(ptr)?.len();
-                this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
+                this.write_scalar(
+                    Scalar::from_machine_usize(u64::try_from(n).unwrap(), this),
+                    dest,
+                )?;
             }
 
             // math functions (note that there are also intrinsics for some other functions)
@@ -835,7 +855,8 @@ fn emulate_foreign_item_by_name(
                 let a = this.read_scalar(a)?.to_u64()?;
                 let b = this.read_scalar(b)?.to_u64()?;
 
-                #[allow(clippy::integer_arithmetic)] // adding two u64 and a u8 cannot wrap in a u128
+                #[allow(clippy::integer_arithmetic)]
+                // adding two u64 and a u8 cannot wrap in a u128
                 let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b);
                 #[allow(clippy::integer_arithmetic)] // it's a u128, we can shift by 64
                 let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
@@ -845,7 +866,9 @@ fn emulate_foreign_item_by_name(
                 let sum_field = this.place_field(dest, 1)?;
                 this.write_scalar(Scalar::from_u64(sum), &sum_field)?;
             }
-            "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => {
+            "llvm.x86.sse2.pause"
+                if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" =>
+            {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.yield_active_thread();
             }
@@ -853,7 +876,8 @@ fn emulate_foreign_item_by_name(
                 let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
                 let arg = this.read_scalar(arg)?.to_i32()?;
                 match arg {
-                    15 => { // SY ("full system scope")
+                    // SY ("full system scope")
+                    15 => {
                         this.yield_active_thread();
                     }
                     _ => {
@@ -863,11 +887,18 @@ fn emulate_foreign_item_by_name(
             }
 
             // Platform-specific shims
-            _ => match this.tcx.sess.target.os.as_ref() {
-                target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
-                "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
-                target => throw_unsup_format!("the target `{}` is not supported", target),
-            }
+            _ =>
+                return match this.tcx.sess.target.os.as_ref() {
+                    target_os if target_os_is_unix(target_os) =>
+                        shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "windows" =>
+                        shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(
+                            this, link_name, abi, args, dest,
+                        ),
+                    _ => Ok(EmulateByNameResult::NotSupported),
+                },
         };
         // We only fall through to here if we did *not* hit the `_` arm above,
         // i.e., if we actually emulated the function with one of the shims.
index 7768772338a777b73d709b1dbd68985435ee1643..ca31efa486c2717d03795f227ae6530988b7bfc1 100644 (file)
@@ -257,16 +257,11 @@ pub fn on_stack_empty<'tcx>(
                         // And move to the final state.
                         self.0 = Done;
                     }
-                    "wasi" | "none" => {
-                        // No OS, no TLS dtors.
+                    _ => {
+                        // No TLS dtor support.
                         // FIXME: should we do something on wasi?
                         self.0 = Done;
                     }
-                    os => {
-                        throw_unsup_format!(
-                            "the TLS machinery does not know how to handle OS `{os}`"
-                        );
-                    }
                 }
             }
             PthreadDtors(state) => {
index 7f43afb7820b5858367962cb2f3d79ba461cb3f1..d018a7ea252b7ec10e539b4ca4338213a26eab63 100644 (file)
@@ -596,13 +596,13 @@ fn emulate_foreign_item_by_name(
             // Platform-specific shims
             _ => {
                 let target_os = &*this.tcx.sess.target.os;
-                match target_os {
-                    "android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
-                    "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
-                    "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
-                    "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
-                    _ => panic!("unsupported Unix OS {target_os}"),
-                }
+                return match target_os {
+                    "android" => shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+                    "freebsd" => shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+                    "linux" => shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+                    "macos" => shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
+                    _ => Ok(EmulateByNameResult::NotSupported),
+                };
             }
         };
 
index 2c53c482bf9aaee3aa0a4c8eefbab86517a1ebb1..af38ceb1d4c7df7202ac8a0ea2e24d750b07ce30 100644 (file)
@@ -83,27 +83,27 @@ version = "0.1.0"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.44"
+version = "1.0.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.21"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.145"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -119,9 +119,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.101"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -130,6 +130,6 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.4"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
index c728e7c0778db8dd70b9ce77acafa85c37dc24aa..bf7f0411bedb711debf27c98944ce1a21cbf7b0d 100644 (file)
@@ -50,18 +50,18 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.19"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.137"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 
 [[package]]
 name = "lock_api"
@@ -115,9 +115,9 @@ dependencies = [
 
 [[package]]
 name = "num_cpus"
-version = "1.14.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -145,9 +145,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
 dependencies = [
  "cfg-if",
  "libc",
@@ -170,18 +170,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.47"
+version = "1.0.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.21"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
 dependencies = [
  "proc-macro2",
 ]
@@ -258,9 +258,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.103"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -269,9 +269,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.22.0"
+version = "1.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
+checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
 dependencies = [
  "autocfg",
  "bytes",
@@ -284,14 +284,14 @@ dependencies = [
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "winapi",
+ "windows-sys",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "1.8.0"
+version = "1.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
+checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -300,9 +300,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.5"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
 
 [[package]]
 name = "wasi"
index 3a80e8c96441962ad14ac09ada234f5413765bb5..1df35bbbe2f9510d00e7799fb5915775dc183203 100644 (file)
@@ -9,13 +9,15 @@ edition = "2021"
 
 [dependencies]
 # all dependencies (and their transitive ones) listed here can be used in `tests/`.
-tokio = { version = "1.0", features = ["full"] }
 libc = "0.2"
-page_size = "0.5"
 num_cpus = "1.10.1"
 
 getrandom_1 = { package = "getrandom", version = "0.1" }
 getrandom = { version = "0.2" }
 rand = { version = "0.8", features = ["small_rng"] }
 
+[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
+page_size = "0.5"
+tokio = { version = "1.0", features = ["full"] }
+
 [workspace]
diff --git a/src/tools/miri/tests/avr.json b/src/tools/miri/tests/avr.json
new file mode 100644 (file)
index 0000000..1e00b0f
--- /dev/null
@@ -0,0 +1,25 @@
+{
+  "arch": "avr",
+  "cpu": "atmega328p",
+  "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",
+  "env": "",
+  "executables": true,
+  "linker": "avr-gcc",
+  "linker-flavor": "gcc",
+  "linker-is-gnu": true,
+  "llvm-target": "avr-unknown-unknown",
+  "os": "unknown",
+  "position-independent-executables": false,
+  "exe-suffix": ".elf",
+  "eh-frame-header": false,
+  "pre-link-args": {
+    "gcc": ["-mmcu=atmega328p"]
+  },
+  "late-link-args": {
+    "gcc": ["-lgcc"]
+  },
+  "target-c-int-width": "16",
+  "target-endian": "little",
+  "target-pointer-width": "16",
+  "vendor": "unknown"
+}
index 3aaeb632cad7b66412891a372fbd92068cbe7d2c..3540c75b73a12ceacef1485eeb3d4b4d2818bf5d 100644 (file)
@@ -1,5 +1,6 @@
 //@only-target-linux
 //@only-on-host
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
 
 extern "C" {
     fn foo();
@@ -7,6 +8,6 @@
 
 fn main() {
     unsafe {
-        foo(); //~ ERROR: unsupported operation: can't call foreign function: foo
+        foo(); //~ ERROR: unsupported operation: can't call foreign function `foo`
     }
 }
index f649f0ae43e30992634235fd3f6b160d6e857ec1..e9bc322047195ff89879969e76ba05a95b7a91de 100644 (file)
@@ -1,8 +1,8 @@
-error: unsupported operation: can't call foreign function: foo
+error: unsupported operation: can't call foreign function `foo` on $OS
   --> $DIR/function_not_in_so.rs:LL:CC
    |
 LL |         foo();
-   |         ^^^^^ can't call foreign function: foo
+   |         ^^^^^ can't call foreign function `foo` on $OS
    |
    = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
    = note: BACKTRACE:
index fb0e7986bb5e6042caebb2a7508e4f0a0e348cf3..624ad1bda582f21f00e0330287eb744ece22711f 100644 (file)
@@ -1,3 +1,4 @@
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
 // Make sure we pretend the allocation symbols don't exist when there is no allocator
 
 #![feature(lang_items, start)]
@@ -10,7 +11,7 @@
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
     unsafe {
-        __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function: __rust_alloc
+        __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc`
     }
 
     0
index ea70970ae0fefbf499318cf12de8a12d68fb35dc..fe6a22fadc9e2ea85f1f3ce058ae340fb90bee3d 100644 (file)
@@ -1,8 +1,8 @@
-error: unsupported operation: can't call foreign function: __rust_alloc
+error: unsupported operation: can't call foreign function `__rust_alloc` on $OS
   --> $DIR/no_global_allocator.rs:LL:CC
    |
 LL |         __rust_alloc(1, 1);
-   |         ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc
+   |         ^^^^^^^^^^^^^^^^^^ can't call foreign function `__rust_alloc` on $OS
    |
    = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
    = note: BACKTRACE:
index dfd099e734b99a6b619135bc89905fa81c26dcbb..44f032fbabe0f57f548727b9c503ef9c95cfa912 100644 (file)
@@ -1,9 +1,11 @@
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
+
 fn main() {
     extern "Rust" {
         fn foo();
     }
 
     unsafe {
-        foo(); //~ ERROR: unsupported operation: can't call foreign function: foo
+        foo(); //~ ERROR: unsupported operation: can't call foreign function `foo`
     }
 }
index fde5fb78ac08a2c50d0f0de01c013900fc91538f..519f6d182d7d8b3d63fe2748b6a24fbc31287a2d 100644 (file)
@@ -1,8 +1,8 @@
-error: unsupported operation: can't call foreign function: foo
+error: unsupported operation: can't call foreign function `foo` on $OS
   --> $DIR/unsupported_foreign_function.rs:LL:CC
    |
 LL |         foo();
-   |         ^^^^^ can't call foreign function: foo
+   |         ^^^^^ can't call foreign function `foo` on $OS
    |
    = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/unsupported_incomplete_function.rs b/src/tools/miri/tests/fail/unsupported_incomplete_function.rs
new file mode 100644 (file)
index 0000000..6ef842c
--- /dev/null
@@ -0,0 +1,11 @@
+//! `signal()` is special on Linux and macOS that it's only supported within libstd.
+//! The implementation is not complete enough to permit user code to call it.
+//@ignore-target-windows: No libc on Windows
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
+
+fn main() {
+    unsafe {
+        libc::signal(libc::SIGPIPE, libc::SIG_IGN);
+        //~^ ERROR: unsupported operation: can't call foreign function `signal`
+    }
+}
diff --git a/src/tools/miri/tests/fail/unsupported_incomplete_function.stderr b/src/tools/miri/tests/fail/unsupported_incomplete_function.stderr
new file mode 100644 (file)
index 0000000..ec2bba6
--- /dev/null
@@ -0,0 +1,14 @@
+error: unsupported operation: can't call foreign function `signal` on $OS
+  --> $DIR/unsupported_incomplete_function.rs:LL:CC
+   |
+LL |         libc::signal(libc::SIGPIPE, libc::SIG_IGN);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `signal` on $OS
+   |
+   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/unsupported_incomplete_function.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/unsupported_signal.rs b/src/tools/miri/tests/fail/unsupported_signal.rs
deleted file mode 100644 (file)
index d50041f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-//! `signal()` is special on Linux and macOS that it's only supported within libstd.
-//! The implementation is not complete enough to permit user code to call it.
-//@ignore-target-windows: No libc on Windows
-
-fn main() {
-    unsafe {
-        libc::signal(libc::SIGPIPE, libc::SIG_IGN);
-        //~^ ERROR: unsupported operation: can't call foreign function: signal
-    }
-}
diff --git a/src/tools/miri/tests/fail/unsupported_signal.stderr b/src/tools/miri/tests/fail/unsupported_signal.stderr
deleted file mode 100644 (file)
index d22ecbc..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: unsupported operation: can't call foreign function: signal
-  --> $DIR/unsupported_signal.rs:LL:CC
-   |
-LL |         libc::signal(libc::SIGPIPE, libc::SIG_IGN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal
-   |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-
index a78646528fb125b810f7c7893dd140c1a62d9949..b8301c507724cb7909f089f0529a114ce6e65c04 100644 (file)
@@ -1,4 +1,5 @@
 //@compile-flags: -Zmiri-panic-on-unsupported
+//@normalize-stderr-test: "OS `.*`" -> "$$OS"
 
 fn main() {
     extern "Rust" {
index 9af3e48655f38be504960982400d1d666f74b777..a49dbdae58a6fd873c45218d447f428a23a9b08d 100644 (file)
@@ -1,2 +1,2 @@
-thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:LL:CC
+thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function `foo` on $OS', $DIR/unsupported_foreign_function.rs:LL:CC
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
index 300b5ec61ef38855a07e6bb4955a37aa1c414c00..5b2eee7eed72b4894909c5eecbf014ea0b5ad995 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 300b5ec61ef38855a07e6bb4955a37aa1c414c00
+Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995
index a5f0c0f320a8c58e4261d04199ec8715453caacc..84b16a37a338bcee9ff98a6e47d545955893e72e 100644 (file)
@@ -77,6 +77,8 @@ clap = { version = "3.1.1", features = ["derive", "clap_derive"]}
 curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
 # Ensure `extra_traits` of libc, which is used transitively by Cargo.
 libc = { version = "0.2", features = ["extra_traits"] }
+# Ensure `js` of getrandom, which is (unfortunately) used transitively by Cargo.
+getrandom = { version = "0.2", features = ["js"] }
 # Ensure default features of libz-sys, which are disabled in some scenarios.
 libz-sys = { version = "1.1.2" }
 # Ensure default features of regex, which are disabled in some scenarios.
index d40d9a3cb542abab7c22f30ae0a24aa32336f05d..900ca389436254276107f6dbff349e622b2463d2 100644 (file)
@@ -9,6 +9,9 @@ const path = require("path");
 const os = require('os');
 const {Options, runTest} = require('browser-ui-test');
 
+// If a test fails or errors, we will retry it two more times in case it was a flaky failure.
+const NB_RETRY = 3;
+
 function showHelp() {
     console.log("rustdoc-js options:");
     console.log("  --doc-folder [PATH]        : location of the generated doc folder");
@@ -129,11 +132,59 @@ function char_printer(n_tests) {
     };
 }
 
-/// Sort array by .file_name property
+// Sort array by .file_name property
 function by_filename(a, b) {
     return a.file_name - b.file_name;
 }
 
+async function runTests(opts, framework_options, files, results, status_bar, showTestFailures) {
+    const tests_queue = [];
+
+    for (const testPath of files) {
+        const callback = runTest(testPath, framework_options)
+            .then(out => {
+                const [output, nb_failures] = out;
+                results[nb_failures === 0 ? "successful" : "failed"].push({
+                    file_name: testPath,
+                    output: output,
+                });
+                if (nb_failures === 0) {
+                    status_bar.successful();
+                } else if (showTestFailures) {
+                    status_bar.erroneous();
+                }
+            })
+            .catch(err => {
+                results.errored.push({
+                    file_name: testPath,
+                    output: err,
+                });
+                if (showTestFailures) {
+                    status_bar.erroneous();
+                }
+            })
+            .finally(() => {
+                // We now remove the promise from the tests_queue.
+                tests_queue.splice(tests_queue.indexOf(callback), 1);
+            });
+        tests_queue.push(callback);
+        if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
+            await Promise.race(tests_queue);
+        }
+    }
+    if (tests_queue.length > 0) {
+        await Promise.all(tests_queue);
+    }
+}
+
+function createEmptyResults() {
+    return {
+        successful: [],
+        failed: [],
+        errored: [],
+    };
+}
+
 async function main(argv) {
     let opts = parseOptions(argv.slice(2));
     if (opts === null) {
@@ -144,7 +195,7 @@ async function main(argv) {
     let debug = false;
     // Run tests in sequentially
     let headless = true;
-    const options = new Options();
+    const framework_options = new Options();
     try {
         // This is more convenient that setting fields one by one.
         let args = [
@@ -169,13 +220,12 @@ async function main(argv) {
             args.push("--executable-path");
             args.push(opts["executable_path"]);
         }
-        options.parseArguments(args);
+        framework_options.parseArguments(args);
     } catch (error) {
         console.error(`invalid argument: ${error}`);
         process.exit(1);
     }
 
-    let failed = false;
     let files;
     if (opts["files"].length === 0) {
         files = fs.readdirSync(opts["tests_folder"]);
@@ -187,6 +237,9 @@ async function main(argv) {
         console.error("rustdoc-gui: No test selected");
         process.exit(2);
     }
+    files.forEach((file_name, index) => {
+        files[index] = path.join(opts["tests_folder"], file_name);
+    });
     files.sort();
 
     if (!headless) {
@@ -215,52 +268,29 @@ async function main(argv) {
     };
     process.on('exit', exitHandling);
 
-    const tests_queue = [];
-    let results = {
-        successful: [],
-        failed: [],
-        errored: [],
-    };
+    const originalFilesLen = files.length;
+    let results = createEmptyResults();
     const status_bar = char_printer(files.length);
-    for (let i = 0; i < files.length; ++i) {
-        const file_name = files[i];
-        const testPath = path.join(opts["tests_folder"], file_name);
-        const callback = runTest(testPath, options)
-            .then(out => {
-                const [output, nb_failures] = out;
-                results[nb_failures === 0 ? "successful" : "failed"].push({
-                    file_name: testPath,
-                    output: output,
-                });
-                if (nb_failures > 0) {
-                    status_bar.erroneous();
-                    failed = true;
-                } else {
-                    status_bar.successful();
-                }
-            })
-            .catch(err => {
-                results.errored.push({
-                    file_name: testPath + file_name,
-                    output: err,
-                });
-                status_bar.erroneous();
-                failed = true;
-            })
-            .finally(() => {
-                // We now remove the promise from the tests_queue.
-                tests_queue.splice(tests_queue.indexOf(callback), 1);
-            });
-        tests_queue.push(callback);
-        if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
-            await Promise.race(tests_queue);
+
+    let new_results;
+    for (let it = 0; it < NB_RETRY && files.length > 0; ++it) {
+        new_results = createEmptyResults();
+        await runTests(opts, framework_options, files, new_results, status_bar, it + 1 >= NB_RETRY);
+        Array.prototype.push.apply(results.successful, new_results.successful);
+        // We generate the new list of files with the previously failing tests.
+        files = Array.prototype.concat(new_results.failed, new_results.errored);
+        if (files.length > originalFilesLen / 2) {
+            // If we have too many failing tests, it's very likely not flaky failures anymore so
+            // no need to retry.
+            break;
         }
     }
-    if (tests_queue.length > 0) {
-        await Promise.all(tests_queue);
-    }
+
     status_bar.finish();
 
+    Array.prototype.push.apply(results.failed, new_results.failed);
+    Array.prototype.push.apply(results.errored, new_results.errored);
+
     // We don't need this listener anymore.
     process.removeListener("exit", exitHandling);
 
@@ -287,7 +317,7 @@ async function main(argv) {
         });
     }
 
-    if (failed) {
+    if (results.failed.length > 0 || results.errored.length > 0) {
         process.exit(1);
     }
 }
index 1d1ef525f23fa38ba259bdd45ea0e0e6e86a8549..0c27bcacfb83ca73c77744e4ff02b6d640f63215 100644 (file)
 extern crate rustc_session;
 extern crate rustc_span;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
index d5177a2057b8ab05fb3daebe466de1d87dc32710..c1991e8d2c80800ef354d7ccc5554928349450be 100644 (file)
@@ -688,7 +688,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
 
                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
             }
-            ast::TyKind::Rptr(ref lifetime, ref mt) => {
+            ast::TyKind::Ref(ref lifetime, ref mt) => {
                 let mut_str = format_mutability(mt.mutbl);
                 let mut_len = mut_str.len();
                 let mut result = String::with_capacity(128);
@@ -1059,7 +1059,7 @@ pub(crate) fn can_be_overflowed_type(
 ) -> bool {
     match ty.kind {
         ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
-        ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
+        ast::TyKind::Ref(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
             can_be_overflowed_type(context, &*mutty.ty, len)
         }
         _ => false,
index 4a58c3946e12dae2c3ac6c441c60bc5c9b8b6f1f..d3734e90b7ffa97c47633d0a0b6909356ea26160 100644 (file)
@@ -20,6 +20,7 @@ fn bindings() {
                 category,
                 span,
                 &format!("`{}`", name),
+                "function",
             ),
         (
             ref name,
index 97d038da702d5b727497f787702ad559fe87def8..5f5ae3a65efa81c34498c40c6de57fd59ddd81af 100644 (file)
@@ -11,6 +11,8 @@ miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
+semver = "1.0.14"
+termcolor = "1.1.3"
 
 [[bin]]
 name = "rust-tidy"
index 75454cbdc5fe6a6f5288adda9f3ebc7399e0ce83..29501d2d3b6be975e94faa0b46e06beacc1426f4 100644 (file)
@@ -40,6 +40,8 @@
     ("im-rc", "MPL-2.0+"),                                   // cargo
     ("sized-chunks", "MPL-2.0+"),                            // cargo via im-rc
     ("bitmaps", "MPL-2.0+"),                                 // cargo via im-rc
+    ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"),    // cargo via pasetors
+    ("subtle", "BSD-3-Clause"),                              // cargo via pasetors
     ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
     ("snap", "BSD-3-Clause"),    // rustc
     ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
@@ -96,6 +98,7 @@
     "autocfg",
     "bitflags",
     "block-buffer",
+    "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "cc",
     "cfg-if",
     "chalk-derive",
     "itertools",
     "itoa",
     "jobserver",
+    "js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "lazy_static",
     "libc",
     "libloading",
     "rand",
     "rand_chacha",
     "rand_core",
-    "rand_hc",
     "rand_xorshift",
     "rand_xoshiro",
     "redox_syscall",
     "stable_deref_trait",
     "stacker",
     "static_assertions",
+    "subtle", // dependency of cargo (via pasetors)
     "syn",
     "synstructure",
     "tempfile",
     "valuable",
     "version_check",
     "wasi",
+    // vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown.
+    "wasm-bindgen",
+    "wasm-bindgen-backend",
+    "wasm-bindgen-macro",
+    "wasm-bindgen-macro-support",
+    "wasm-bindgen-shared",
+    // ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-util",
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
new file mode 100644 (file)
index 0000000..9aacc07
--- /dev/null
@@ -0,0 +1,386 @@
+//! Tidy check to ensure error codes are properly documented and tested.
+//!
+//! Overview of check:
+//!
+//! 1. We create a list of error codes used by the compiler. Error codes are extracted from `compiler/rustc_error_codes/src/error_codes.rs`.
+//!
+//! 2. We check that the error code has a long-form explanation in `compiler/rustc_error_codes/src/error_codes/`.
+//!   - The explanation is expected to contain a `doctest` that fails with the correct error code. (`EXEMPT_FROM_DOCTEST` *currently* bypasses this check)
+//!   - Note that other stylistic conventions for markdown files are checked in the `style.rs` tidy check.
+//!
+//! 3. We check that the error code has a UI test in `src/test/ui/error-codes/`.
+//!   - We ensure that there is both a `Exxxx.rs` file and a corresponding `Exxxx.stderr` file.
+//!   - We also ensure that the error code is used in the tests.
+//!   - *Currently*, it is possible to opt-out of this check with the `EXEMPTED_FROM_TEST` constant.
+//!
+//! 4. We check that the error code is actually emitted by the compiler.
+//!   - This is done by searching `compiler/` with a regex.
+
+use std::{ffi::OsStr, fs, path::Path};
+
+use regex::Regex;
+
+use crate::walk::{filter_dirs, walk, walk_many};
+
+const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/error_codes.rs";
+const ERROR_DOCS_PATH: &str = "compiler/rustc_error_codes/src/error_codes/";
+const ERROR_TESTS_PATH: &str = "src/test/ui/error-codes/";
+
+// Error codes that (for some reason) can't have a doctest in their explanation. Error codes are still expected to provide a code example, even if untested.
+const IGNORE_DOCTEST_CHECK: &[&str] =
+    &["E0208", "E0464", "E0570", "E0601", "E0602", "E0640", "E0717"];
+
+// 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", "E0490", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729",
+    "E0789",
+];
+
+macro_rules! verbose_print {
+    ($verbose:expr, $($fmt:tt)*) => {
+        if $verbose {
+            println!("{}", format_args!($($fmt)*));
+        }
+    };
+}
+
+pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut bool) {
+    let mut errors = Vec::new();
+
+    // Stage 1: create list
+    let error_codes = extract_error_codes(root_path, &mut errors, verbose);
+    println!("Found {} error codes", error_codes.len());
+    println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
+
+    // Stage 2: check list has docs
+    let no_longer_emitted = check_error_codes_docs(root_path, &error_codes, &mut errors, verbose);
+
+    // Stage 3: check list has UI tests
+    check_error_codes_tests(root_path, &error_codes, &mut errors, verbose, &no_longer_emitted);
+
+    // Stage 4: check list is emitted by compiler
+    check_error_codes_used(search_paths, &error_codes, &mut errors, &no_longer_emitted, verbose);
+
+    // Print any errors.
+    for error in errors {
+        tidy_error!(bad, "{}", error);
+    }
+}
+
+/// Stage 1: Parses a list of error codes from `error_codes.rs`.
+fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>, verbose: bool) -> Vec<String> {
+    let path = root_path.join(Path::new(ERROR_CODES_PATH));
+    let file =
+        fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
+
+    let mut error_codes = Vec::new();
+    let mut reached_undocumented_codes = false;
+
+    for line in file.lines() {
+        let line = line.trim();
+
+        if !reached_undocumented_codes && line.starts_with('E') {
+            let split_line = line.split_once(':');
+
+            // Extract the error code from the line, emitting a fatal error if it is not in a correct format.
+            let err_code = if let Some(err_code) = split_line {
+                err_code.0.to_owned()
+            } else {
+                errors.push(format!(
+                    "Expected a line with the format `Exxxx: include_str!(\"..\")`, but got \"{}\" \
+                    without a `:` delimiter",
+                    line,
+                ));
+                continue;
+            };
+
+            // If this is a duplicate of another error code, emit a fatal error.
+            if error_codes.contains(&err_code) {
+                errors.push(format!("Found duplicate error code: `{}`", err_code));
+                continue;
+            }
+
+            // Ensure that the line references the correct markdown file.
+            let expected_filename = format!(" include_str!(\"./error_codes/{}.md\"),", err_code);
+            if expected_filename != split_line.unwrap().1 {
+                errors.push(format!(
+                    "Error code `{}` expected to reference docs with `{}` but instead found `{}` in \
+                    `compiler/rustc_error_codes/src/error_codes.rs`",
+                    err_code,
+                    expected_filename,
+                    split_line.unwrap().1,
+                ));
+                continue;
+            }
+
+            error_codes.push(err_code);
+        } else if reached_undocumented_codes && line.starts_with('E') {
+            let err_code = match line.split_once(',') {
+                None => line,
+                Some((err_code, _)) => err_code,
+            }
+            .to_string();
+
+            verbose_print!(verbose, "warning: Error code `{}` is undocumented.", err_code);
+
+            if error_codes.contains(&err_code) {
+                errors.push(format!("Found duplicate error code: `{}`", err_code));
+            }
+
+            error_codes.push(err_code);
+        } else if line == ";" {
+            // Once we reach the undocumented error codes, adapt to different syntax.
+            reached_undocumented_codes = true;
+        }
+    }
+
+    error_codes
+}
+
+/// Stage 2: Checks that long-form error code explanations exist and have doctests.
+fn check_error_codes_docs(
+    root_path: &Path,
+    error_codes: &[String],
+    errors: &mut Vec<String>,
+    verbose: bool,
+) -> Vec<String> {
+    let docs_path = root_path.join(Path::new(ERROR_DOCS_PATH));
+
+    let mut no_longer_emitted_codes = Vec::new();
+
+    walk(&docs_path, &mut |_| false, &mut |entry, contents| {
+        let path = entry.path();
+
+        // Error if the file isn't markdown.
+        if path.extension() != Some(OsStr::new("md")) {
+            errors.push(format!(
+                "Found unexpected non-markdown file in error code docs directory: {}",
+                path.display()
+            ));
+            return;
+        }
+
+        // Make sure that the file is referenced in `error_codes.rs`
+        let filename = path.file_name().unwrap().to_str().unwrap().split_once('.');
+        let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format.
+
+        if error_codes.iter().all(|e| e != err_code) {
+            errors.push(format!(
+                "Found valid file `{}` in error code docs directory without corresponding \
+                entry in `error_code.rs`",
+                path.display()
+            ));
+            return;
+        }
+
+        let (found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted) =
+            check_explanation_has_doctest(&contents, &err_code);
+
+        if emit_ignore_warning {
+            verbose_print!(
+                verbose,
+                "warning: Error code `{err_code}` uses the ignore header. This should not be used, add the error code to the \
+                `IGNORE_DOCTEST_CHECK` constant instead."
+            );
+        }
+
+        if no_longer_emitted {
+            no_longer_emitted_codes.push(err_code.to_owned());
+        }
+
+        if !found_code_example {
+            verbose_print!(
+                verbose,
+                "warning: Error code `{err_code}` doesn't have a code example, all error codes are expected to have one \
+                (even if untested)."
+            );
+            return;
+        }
+
+        let test_ignored = IGNORE_DOCTEST_CHECK.contains(&&err_code);
+
+        // Check that the explanation has a doctest, and if it shouldn't, that it doesn't
+        if !found_proper_doctest && !test_ignored {
+            errors.push(format!(
+                "`{}` doesn't use its own error code in compile_fail example",
+                path.display(),
+            ));
+        } else if found_proper_doctest && test_ignored {
+            errors.push(format!(
+                "`{}` has a compile_fail doctest with its own error code, it shouldn't \
+                be listed in `IGNORE_DOCTEST_CHECK`",
+                path.display(),
+            ));
+        }
+    });
+
+    no_longer_emitted_codes
+}
+
+/// This function returns a tuple indicating whether the provided explanation:
+/// a) has a code example, tested or not.
+/// b) has a valid doctest
+fn check_explanation_has_doctest(explanation: &str, err_code: &str) -> (bool, bool, bool, bool) {
+    let mut found_code_example = false;
+    let mut found_proper_doctest = false;
+
+    let mut emit_ignore_warning = false;
+    let mut no_longer_emitted = false;
+
+    for line in explanation.lines() {
+        let line = line.trim();
+
+        if line.starts_with("```") {
+            found_code_example = true;
+
+            // Check for the `rustdoc` doctest headers.
+            if line.contains("compile_fail") && line.contains(err_code) {
+                found_proper_doctest = true;
+            }
+
+            if line.contains("ignore") {
+                emit_ignore_warning = true;
+                found_proper_doctest = true;
+            }
+        } else if line
+            .starts_with("#### Note: this error code is no longer emitted by the compiler")
+        {
+            no_longer_emitted = true;
+            found_code_example = true;
+            found_proper_doctest = true;
+        }
+    }
+
+    (found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted)
+}
+
+// Stage 3: Checks that each error code has a UI test in the correct directory
+fn check_error_codes_tests(
+    root_path: &Path,
+    error_codes: &[String],
+    errors: &mut Vec<String>,
+    verbose: bool,
+    no_longer_emitted: &[String],
+) {
+    let tests_path = root_path.join(Path::new(ERROR_TESTS_PATH));
+
+    for code in error_codes {
+        let test_path = tests_path.join(format!("{}.stderr", code));
+
+        if !test_path.exists() && !IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
+            verbose_print!(
+                verbose,
+                "warning: Error code `{code}` needs to have at least one UI test in the `src/test/ui/error-codes/` directory`!"
+            );
+            continue;
+        }
+        if IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
+            if test_path.exists() {
+                errors.push(format!(
+                    "Error code `{code}` has a UI test in `src/test/ui/error-codes/{code}.rs`, it shouldn't be listed in `EXEMPTED_FROM_TEST`!"
+                ));
+            }
+            continue;
+        }
+
+        let file = match fs::read_to_string(&test_path) {
+            Ok(file) => file,
+            Err(err) => {
+                verbose_print!(
+                    verbose,
+                    "warning: Failed to read UI test file (`{}`) for `{code}` but the file exists. The test is assumed to work:\n{err}",
+                    test_path.display()
+                );
+                continue;
+            }
+        };
+
+        if no_longer_emitted.contains(code) {
+            // UI tests *can't* contain error codes that are no longer emitted.
+            continue;
+        }
+
+        let mut found_code = false;
+
+        for line in file.lines() {
+            let s = line.trim();
+            // Assuming the line starts with `error[E`, we can substring the error code out.
+            if s.starts_with("error[E") {
+                if &s[6..11] == code {
+                    found_code = true;
+                    break;
+                }
+            };
+        }
+
+        if !found_code {
+            verbose_print!(
+                verbose,
+                "warning: Error code {code}`` has a UI test file, but doesn't contain its own error code!"
+            );
+        }
+    }
+}
+
+/// Stage 4: Search `compiler/` and ensure that every error code is actually used by the compiler and that no undocumented error codes exist.
+fn check_error_codes_used(
+    search_paths: &[&Path],
+    error_codes: &[String],
+    errors: &mut Vec<String>,
+    no_longer_emitted: &[String],
+    verbose: bool,
+) {
+    // We want error codes which match the following cases:
+    //
+    // * foo(a, E0111, a)
+    // * foo(a, E0111)
+    // * foo(E0111, a)
+    // * #[error = "E0111"]
+    let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap();
+
+    let mut found_codes = Vec::new();
+
+    walk_many(search_paths, &mut filter_dirs, &mut |entry, contents| {
+        let path = entry.path();
+
+        // Return early if we aren't looking at a source file.
+        if path.extension() != Some(OsStr::new("rs")) {
+            return;
+        }
+
+        for line in contents.lines() {
+            // We want to avoid parsing error codes in comments.
+            if line.trim_start().starts_with("//") {
+                continue;
+            }
+
+            for cap in regex.captures_iter(line) {
+                if let Some(error_code) = cap.get(1) {
+                    let error_code = error_code.as_str().to_owned();
+
+                    if !error_codes.contains(&error_code) {
+                        // This error code isn't properly defined, we must error.
+                        errors.push(format!("Error code `{}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/error_codes.rs`.", error_code));
+                        continue;
+                    }
+
+                    // This error code can now be marked as used.
+                    found_codes.push(error_code);
+                }
+            }
+        }
+    });
+
+    for code in error_codes {
+        if !found_codes.contains(code) && !no_longer_emitted.contains(code) {
+            errors.push(format!("Error code `{code}` exists, but is not emitted by the compiler!"))
+        }
+
+        if found_codes.contains(code) && no_longer_emitted.contains(code) {
+            verbose_print!(
+                verbose,
+                "warning: Error code `{code}` is used when it's marked as \"no longer emitted\""
+            );
+        }
+    }
+}
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
deleted file mode 100644 (file)
index 49fc2ce..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-//! Checks that all error codes have at least one test to prevent having error
-//! codes that are silently not thrown by the compiler anymore.
-
-use crate::walk::{filter_dirs, walk};
-use std::collections::{HashMap, HashSet};
-use std::ffi::OsStr;
-use std::fs::read_to_string;
-use std::path::Path;
-
-use regex::Regex;
-
-// A few of those error codes can't be tested but all the others can and *should* be tested!
-const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0313", "E0461", "E0465", "E0476", "E0490", "E0514", "E0519", "E0523", "E0554", "E0640",
-    "E0717", "E0729", "E0789",
-];
-
-// Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E0729"];
-
-// If the file path contains any of these, we don't want to try to extract error codes from it.
-//
-// We need to declare each path in the windows version (with backslash).
-const PATHS_TO_IGNORE_FOR_EXTRACTION: &[&str] =
-    &["src/test/", "src\\test\\", "src/doc/", "src\\doc\\", "src/tools/", "src\\tools\\"];
-
-#[derive(Default, Debug)]
-struct ErrorCodeStatus {
-    has_test: bool,
-    has_explanation: bool,
-    is_used: bool,
-}
-
-fn check_error_code_explanation(
-    f: &str,
-    error_codes: &mut HashMap<String, ErrorCodeStatus>,
-    err_code: String,
-) -> bool {
-    let mut invalid_compile_fail_format = false;
-    let mut found_error_code = false;
-
-    for line in f.lines() {
-        let s = line.trim();
-        if s.starts_with("```") {
-            if s.contains("compile_fail") && s.contains('E') {
-                if !found_error_code {
-                    error_codes.get_mut(&err_code).map(|x| x.has_test = true);
-                    found_error_code = true;
-                }
-            } else if s.contains("compile-fail") {
-                invalid_compile_fail_format = true;
-            }
-        } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
-            if !found_error_code {
-                error_codes.get_mut(&err_code).map(|x| x.has_test = true);
-                found_error_code = true;
-            }
-        }
-    }
-    invalid_compile_fail_format
-}
-
-fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &str) -> bool {
-    let mut ignore_found = false;
-
-    for line in f.lines() {
-        let s = line.trim();
-        if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
-            return true;
-        }
-        if s.starts_with("```") {
-            if s.contains("compile_fail") && s.contains(err_code) {
-                return true;
-            } else if s.contains("ignore") {
-                // It's very likely that we can't actually make it fail compilation...
-                ignore_found = true;
-            }
-        }
-    }
-    ignore_found
-}
-
-macro_rules! some_or_continue {
-    ($e:expr) => {
-        match $e {
-            Some(e) => e,
-            None => continue,
-        }
-    };
-}
-
-fn extract_error_codes(
-    f: &str,
-    error_codes: &mut HashMap<String, ErrorCodeStatus>,
-    path: &Path,
-    errors: &mut Vec<String>,
-) {
-    let mut reached_no_explanation = false;
-
-    for line in f.lines() {
-        let s = line.trim();
-        if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") {
-            let err_code = s
-                .split_once(':')
-                .expect(
-                    format!(
-                        "Expected a line with the format `E0xxx: include_str!(\"..\")`, but got {} \
-                         without a `:` delimiter",
-                        s,
-                    )
-                    .as_str(),
-                )
-                .0
-                .to_owned();
-            error_codes.entry(err_code.clone()).or_default().has_explanation = true;
-
-            // Now we extract the tests from the markdown file!
-            let md_file_name = match s.split_once("include_str!(\"") {
-                None => continue,
-                Some((_, md)) => match md.split_once("\")") {
-                    None => continue,
-                    Some((file_name, _)) => file_name,
-                },
-            };
-            let path = some_or_continue!(path.parent())
-                .join(md_file_name)
-                .canonicalize()
-                .expect("failed to canonicalize error explanation file path");
-            match read_to_string(&path) {
-                Ok(content) => {
-                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
-                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
-                        errors.push(format!(
-                            "`{}` doesn't use its own error code in compile_fail example",
-                            path.display(),
-                        ));
-                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
-                        errors.push(format!(
-                            "`{}` has a compile_fail example with its own error code, it shouldn't \
-                             be listed in IGNORE_EXPLANATION_CHECK!",
-                            path.display(),
-                        ));
-                    }
-                    if check_error_code_explanation(&content, error_codes, err_code) {
-                        errors.push(format!(
-                            "`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
-                            path.display(),
-                        ));
-                    }
-                }
-                Err(e) => {
-                    eprintln!("Couldn't read `{}`: {}", path.display(), e);
-                }
-            }
-        } else if reached_no_explanation && s.starts_with('E') {
-            let err_code = match s.split_once(',') {
-                None => s,
-                Some((err_code, _)) => err_code,
-            }
-            .to_string();
-            if !error_codes.contains_key(&err_code) {
-                // this check should *never* fail!
-                error_codes.insert(err_code, ErrorCodeStatus::default());
-            }
-        } else if s == ";" {
-            reached_no_explanation = true;
-        }
-    }
-}
-
-fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, ErrorCodeStatus>) {
-    for line in f.lines() {
-        let s = line.trim();
-        if s.starts_with("error[E") || s.starts_with("warning[E") {
-            let err_code = match s.split_once(']') {
-                None => continue,
-                Some((err_code, _)) => match err_code.split_once('[') {
-                    None => continue,
-                    Some((_, err_code)) => err_code,
-                },
-            };
-            error_codes.entry(err_code.to_owned()).or_default().has_test = true;
-        }
-    }
-}
-
-fn extract_error_codes_from_source(
-    f: &str,
-    error_codes: &mut HashMap<String, ErrorCodeStatus>,
-    regex: &Regex,
-) {
-    for line in f.lines() {
-        if line.trim_start().starts_with("//") {
-            continue;
-        }
-        for cap in regex.captures_iter(line) {
-            if let Some(error_code) = cap.get(1) {
-                error_codes.entry(error_code.as_str().to_owned()).or_default().is_used = true;
-            }
-        }
-    }
-}
-
-pub fn check(paths: &[&Path], bad: &mut bool) {
-    let mut errors = Vec::new();
-    let mut found_explanations = 0;
-    let mut found_tests = 0;
-    let mut error_codes: HashMap<String, ErrorCodeStatus> = HashMap::new();
-    let mut explanations: HashSet<String> = HashSet::new();
-    // We want error codes which match the following cases:
-    //
-    // * foo(a, E0111, a)
-    // * foo(a, E0111)
-    // * foo(E0111, a)
-    // * #[error = "E0111"]
-    let regex = Regex::new(r#"[(,"\s](E\d{4})[,)"]"#).unwrap();
-
-    println!("Checking which error codes lack tests...");
-
-    for path in paths {
-        walk(path, &mut filter_dirs, &mut |entry, contents| {
-            let file_name = entry.file_name();
-            let entry_path = entry.path();
-
-            if file_name == "error_codes.rs" {
-                extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
-                found_explanations += 1;
-            } else if entry_path.extension() == Some(OsStr::new("stderr")) {
-                extract_error_codes_from_tests(contents, &mut error_codes);
-                found_tests += 1;
-            } else if entry_path.extension() == Some(OsStr::new("rs")) {
-                let path = entry.path().to_string_lossy();
-                if PATHS_TO_IGNORE_FOR_EXTRACTION.iter().all(|c| !path.contains(c)) {
-                    extract_error_codes_from_source(contents, &mut error_codes, &regex);
-                }
-            } else if entry_path
-                .parent()
-                .and_then(|p| p.file_name())
-                .map(|p| p == "error_codes")
-                .unwrap_or(false)
-                && entry_path.extension() == Some(OsStr::new("md"))
-            {
-                explanations.insert(file_name.to_str().unwrap().replace(".md", ""));
-            }
-        });
-    }
-    if found_explanations == 0 {
-        eprintln!("No error code explanation was tested!");
-        *bad = true;
-    }
-    if found_tests == 0 {
-        eprintln!("No error code was found in compilation errors!");
-        *bad = true;
-    }
-    if explanations.is_empty() {
-        eprintln!("No error code explanation was found!");
-        *bad = true;
-    }
-    if errors.is_empty() {
-        println!("Found {} error codes", error_codes.len());
-
-        for (err_code, error_status) in &error_codes {
-            if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
-                errors.push(format!("Error code {err_code} needs to have at least one UI test!"));
-            } else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
-                errors.push(format!(
-                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
-                    err_code
-                ));
-            }
-            if !error_status.is_used && !error_status.has_explanation {
-                errors.push(format!(
-                    "Error code {} isn't used and doesn't have an error explanation, it should be \
-                     commented in error_codes.rs file",
-                    err_code
-                ));
-            }
-        }
-    }
-    if errors.is_empty() {
-        // Checking if local constants need to be cleaned.
-        for err_code in EXEMPTED_FROM_TEST {
-            match error_codes.get(err_code.to_owned()) {
-                Some(status) => {
-                    if status.has_test {
-                        errors.push(format!(
-                            "{} error code has a test and therefore should be \
-                            removed from the `EXEMPTED_FROM_TEST` constant",
-                            err_code
-                        ));
-                    }
-                }
-                None => errors.push(format!(
-                    "{} error code isn't used anymore and therefore should be removed \
-                        from `EXEMPTED_FROM_TEST` constant",
-                    err_code
-                )),
-            }
-        }
-    }
-    if errors.is_empty() {
-        for explanation in explanations {
-            if !error_codes.contains_key(&explanation) {
-                errors.push(format!(
-                    "{} error code explanation should be listed in `error_codes.rs`",
-                    explanation
-                ));
-            }
-        }
-    }
-    errors.sort();
-    for err in &errors {
-        eprintln!("{err}");
-    }
-    println!("Found {} error(s) in error codes", errors.len());
-    if !errors.is_empty() {
-        *bad = true;
-    }
-    println!("Done!");
-}
diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs
deleted file mode 100644 (file)
index fe5fd72..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-//! Tidy check to verify the validity of long error diagnostic codes.
-//!
-//! This ensures that error codes are used at most once and also prints out some
-//! statistics about the error codes.
-
-use crate::walk::{filter_dirs, walk};
-use std::collections::HashMap;
-use std::path::Path;
-
-pub fn check(path: &Path, bad: &mut bool) {
-    let mut map: HashMap<_, Vec<_>> = HashMap::new();
-    walk(
-        path,
-        &mut |path| filter_dirs(path) || path.ends_with("src/test"),
-        &mut |entry, contents| {
-            let file = entry.path();
-            let filename = file.file_name().unwrap().to_string_lossy();
-            if filename != "error_codes.rs" {
-                return;
-            }
-
-            // In the `register_long_diagnostics!` macro, entries look like this:
-            //
-            // ```
-            // EXXXX: r##"
-            // <Long diagnostic message>
-            // "##,
-            // ```
-            //
-            // and these long messages often have error codes themselves inside
-            // them, but we don't want to report duplicates in these cases. This
-            // variable keeps track of whether we're currently inside one of these
-            // long diagnostic messages.
-            let mut inside_long_diag = false;
-            for (num, line) in contents.lines().enumerate() {
-                if inside_long_diag {
-                    inside_long_diag = !line.contains("\"##");
-                    continue;
-                }
-
-                let mut search = line;
-                while let Some(i) = search.find('E') {
-                    search = &search[i + 1..];
-                    let code = if search.len() > 4 { search[..4].parse::<u32>() } else { continue };
-                    let code = match code {
-                        Ok(n) => n,
-                        Err(..) => continue,
-                    };
-                    map.entry(code).or_default().push((file.to_owned(), num + 1, line.to_owned()));
-                    break;
-                }
-
-                inside_long_diag = line.contains("r##\"");
-            }
-        },
-    );
-
-    let mut max = 0;
-    for (&code, entries) in map.iter() {
-        if code > max {
-            max = code;
-        }
-        if entries.len() == 1 {
-            continue;
-        }
-
-        tidy_error!(bad, "duplicate error code: {}", code);
-        for &(ref file, line_num, ref line) in entries.iter() {
-            tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line);
-        }
-    }
-
-    if !*bad {
-        println!("* {} error codes", map.len());
-        println!("* highest error code: E{:04}", max);
-    }
-}
index 31224fdf1eacfb5ecba627c3e16c3e720163a9db..7701dce2df1731057bacc80f8d27f2f5eb31d08e 100644 (file)
@@ -12,8 +12,8 @@ fn test_try_from_invalid_version() {
 
 #[test]
 fn test_try_from_single() {
-    assert_eq!("1.32.0".parse(), Ok(Version { parts: [1, 32, 0] }));
-    assert_eq!("1.0.0".parse(), Ok(Version { parts: [1, 0, 0] }));
+    assert_eq!("1.32.0".parse(), Ok(Version::Explicit { parts: [1, 32, 0] }));
+    assert_eq!("1.0.0".parse(), Ok(Version::Explicit { parts: [1, 0, 0] }));
 }
 
 #[test]
index 698e4850bea9bdf1e8d94875c2ffde8f8e358696..15c641d748c8e414ba62e728eaa2b7a7106ea163 100644 (file)
@@ -3,6 +3,10 @@
 //! This library contains the tidy lints and exposes it
 //! to be used by tools.
 
+use std::fmt::Display;
+
+use termcolor::WriteColor;
+
 /// A helper macro to `unwrap` a result except also print out details like:
 ///
 /// * The expression that failed
@@ -26,25 +30,33 @@ macro_rules! t {
 }
 
 macro_rules! tidy_error {
-    ($bad:expr, $fmt:expr) => ({
-        *$bad = true;
-        eprint!("tidy error: ");
-        eprintln!($fmt);
-    });
-    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
-        *$bad = true;
-        eprint!("tidy error: ");
-        eprintln!($fmt, $($arg)*);
+    ($bad:expr, $($fmt:tt)*) => ({
+        $crate::tidy_error($bad, format_args!($($fmt)*)).expect("failed to output error");
     });
 }
 
+fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
+    use std::io::Write;
+    use termcolor::{Color, ColorChoice, ColorSpec, StandardStream};
+
+    *bad = true;
+
+    let mut stderr = StandardStream::stdout(ColorChoice::Auto);
+    stderr.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
+
+    write!(&mut stderr, "tidy error")?;
+    stderr.set_color(&ColorSpec::new())?;
+
+    writeln!(&mut stderr, ": {args}")?;
+    Ok(())
+}
+
 pub mod alphabetical;
 pub mod bins;
 pub mod debug_artifacts;
 pub mod deps;
 pub mod edition;
-pub mod error_codes_check;
-pub mod errors;
+pub mod error_codes;
 pub mod extdeps;
 pub mod features;
 pub mod mir_opt_tests;
@@ -56,3 +68,4 @@ macro_rules! tidy_error {
 pub mod unit_tests;
 pub mod unstable_book;
 pub mod walk;
+pub mod x_version;
index 6714c63ee62a143a923f84088101cc99ec1142d1..a5685ba7c942c31980d59c4d0348f32f88e966ec 100644 (file)
@@ -27,6 +27,7 @@ fn main() {
     let src_path = root_path.join("src");
     let library_path = root_path.join("library");
     let compiler_path = root_path.join("compiler");
+    let librustdoc_path = src_path.join("librustdoc");
 
     let args: Vec<String> = env::args().skip(1).collect();
 
@@ -58,7 +59,7 @@ macro_rules! check {
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
-                    $p::check($($args),* , &mut flag);
+                    $p::check($($args, )* &mut flag);
                     if (flag) {
                         bad.store(true, Ordering::Relaxed);
                     }
@@ -79,8 +80,7 @@ macro_rules! check {
         check!(mir_opt_tests, &src_path, bless);
 
         // Checks that only make sense for the compiler.
-        check!(errors, &compiler_path);
-        check!(error_codes_check, &[&src_path, &compiler_path]);
+        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
 
         // Checks that only make sense for the std libs.
         check!(pal, &library_path);
@@ -107,6 +107,8 @@ macro_rules! check {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
+        check!(x_version, &root_path, &cargo);
+
         let collected = {
             drain_handles(&mut handles);
 
index f91e38262f64ff8fd1800c99b1cc10ec85856569..b293efdc585add09efac5a0b3d07de5d5d099b0d 100644 (file)
@@ -15,6 +15,7 @@
 //!
 //! A number of these checks can be opted-out of with various directives of the form:
 //! `// ignore-tidy-CHECK-NAME`.
+// ignore-tidy-dbg
 
 use crate::walk::{filter_dirs, walk};
 use regex::{Regex, RegexSet};
@@ -24,6 +25,7 @@
 /// displayed on the console with --example.
 const ERROR_CODE_COLS: usize = 80;
 const COLS: usize = 100;
+const GOML_COLS: usize = 120;
 
 const LINES: usize = 3000;
 
@@ -63,6 +65,8 @@
     3735927486, 3735932941, 4027431614, 4276992702,
 ];
 
+const INTERNAL_COMPILER_DOCS_LINE: &str = "#### This error code is internal to the compiler and will not be emitted with normal Rust code.";
+
 /// Parser states for `line_is_url`.
 #[derive(Clone, Copy, PartialEq)]
 #[allow(non_camel_case_types)]
@@ -131,6 +135,8 @@ fn long_line_is_ok(extension: &str, is_error_code: bool, max_columns: usize, lin
         "ftl" => true,
         // non-error code markdown is allowed to be any length
         "md" if !is_error_code => true,
+        // HACK(Ezrashaw): there is no way to split a markdown header over multiple lines
+        "md" if line == INTERNAL_COMPILER_DOCS_LINE => true,
         _ => line_is_url(is_error_code, max_columns, line) || should_ignore(line),
     }
 }
@@ -229,7 +235,8 @@ fn skip(path: &Path) -> bool {
     walk(path, &mut skip, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
-        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl"];
+        let extensions =
+            [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css", ".ftl", ".goml"];
         if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") {
             return;
         }
@@ -254,8 +261,15 @@ fn skip(path: &Path) -> bool {
 
         let extension = file.extension().unwrap().to_string_lossy();
         let is_error_code = extension == "md" && is_in(file, "src", "error_codes");
+        let is_goml_code = extension == "goml";
 
-        let max_columns = if is_error_code { ERROR_CODE_COLS } else { COLS };
+        let max_columns = if is_error_code {
+            ERROR_CODE_COLS
+        } else if is_goml_code {
+            GOML_COLS
+        } else {
+            COLS
+        };
 
         let can_contain = contents.contains("// ignore-tidy-")
             || contents.contains("# ignore-tidy-")
@@ -278,6 +292,7 @@ fn skip(path: &Path) -> bool {
         let mut skip_leading_newlines =
             contains_ignore_directive(can_contain, &contents, "leading-newlines");
         let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
+        let mut skip_dbg = contains_ignore_directive(can_contain, &contents, "dbg");
         let mut leading_new_lines = false;
         let mut trailing_new_lines = 0;
         let mut lines = 0;
@@ -306,6 +321,21 @@ fn skip(path: &Path) -> bool {
             let mut err = |msg: &str| {
                 tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
             };
+
+            if trimmed.contains("dbg!")
+                && !trimmed.starts_with("//")
+                && !file
+                    .ancestors()
+                    .any(|a| a.ends_with("src/test") || a.ends_with("library/alloc/tests"))
+                && filename != "tests.rs"
+            {
+                suppressible_tidy_err!(
+                    err,
+                    skip_dbg,
+                    "`dbg!` macro is intended as a debugging tool. It should not be in version control."
+                )
+            }
+
             if !under_rustfmt
                 && line.chars().count() > max_columns
                 && !long_line_is_ok(&extension, is_error_code, max_columns, line)
index f746bdeffd7ca18b5c731506086a87d15645bc1a..166d09fa8b06897f635b2decf10d11abdd9cc892 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 = 2020;
+const ISSUES_ENTRY_LIMIT: usize = 1998;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     for dir in Walk::new(&path.join("test/ui")) {
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
new file mode 100644 (file)
index 0000000..5dc6a05
--- /dev/null
@@ -0,0 +1,65 @@
+use semver::Version;
+use std::io::ErrorKind;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+    let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
+    // This runs the command inside a temporary directory.
+    // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
+    let temp_result = Command::new("x")
+        .arg("--wrapper-version")
+        .current_dir(std::env::temp_dir())
+        .stdout(Stdio::piped())
+        .spawn();
+
+    let (child, temp_child) = match (result, temp_result) {
+        (Ok(child), Ok(temp_child)) => (child, temp_child),
+        (Err(e), _) | (_, Err(e)) => match e.kind() {
+            ErrorKind::NotFound => return,
+            _ => return tidy_error!(bad, "failed to run `x`: {}", e),
+        },
+    };
+
+    let output = child.wait_with_output().unwrap();
+    let temp_output = temp_child.wait_with_output().unwrap();
+
+    if output != temp_output {
+        return tidy_error!(
+            bad,
+            "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+        );
+    }
+
+    if output.status.success() {
+        let version = String::from_utf8_lossy(&output.stdout);
+        let version = Version::parse(version.trim_end()).unwrap();
+
+        if let Some(expected) = get_x_wrapper_version(root, cargo) {
+            if version < expected {
+                return tidy_error!(
+                    bad,
+                    "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                );
+            }
+        } else {
+            return tidy_error!(
+                bad,
+                "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
+            );
+        }
+    } else {
+        return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
+    }
+}
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("src/tools/x/Cargo.toml"))
+        .no_deps()
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let mut metadata = t!(cmd.exec());
+    metadata.packages.pop().map(|x| x.version)
+}
index f07ff43efe987fec445e76d8102f6c2bbdcabd4a..01f7187851e38d646d097b78a19f05c6564cc746 100644 (file)
@@ -52,6 +52,14 @@ fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
 }
 
 fn main() {
+    match env::args().skip(1).next().as_deref() {
+        Some("--wrapper-version") => {
+            let version = env!("CARGO_PKG_VERSION");
+            println!("{}", version);
+            return;
+        }
+        _ => {}
+    }
     let current = match env::current_dir() {
         Ok(dir) => dir,
         Err(err) => {
index 22f09396efc6a916652edb662c0a7ff43593f1ef..58108dac496b65e0ce72e6da34bf6fc6df69cf6b 100644 (file)
@@ -479,6 +479,7 @@ compiler = [
     "compiler-team-contributors",
 ]
 libs = [
+    "@cuviper",
     "@joshtriplett",
     "@Mark-Simulacrum",
     "@m-ou-se",
@@ -496,7 +497,6 @@ infra-ci = [
 rustdoc = [
     "@jsha",
     "@GuillaumeGomez",
-    "@CraftSpider",
     "@notriddle",
 ]
 docs = [
diff --git a/x.ps1 b/x.ps1
index 81b98919f436cdad411ed6f3c8c55a4180382720..f324a4676c8e99d5f338eaa0c11020db0f4b5e0b 100755 (executable)
--- a/x.ps1
+++ b/x.ps1
@@ -14,6 +14,12 @@ function Get-Application($app) {
     return Get-Command $app -ErrorAction SilentlyContinue -CommandType Application
 }
 
+function Invoke-Application($application, $arguments) {
+    $process = Start-Process -NoNewWindow -PassThru $application $arguments
+    $process.WaitForExit()
+    Exit $process.ExitCode
+}
+
 foreach ($python in "py", "python3", "python", "python2") {
     # NOTE: this only tests that the command exists in PATH, not that it's actually
     # executable. The latter is not possible in a portable way, see
@@ -23,16 +29,14 @@ foreach ($python in "py", "python3", "python", "python2") {
             # Use python3, not python2
             $xpy_args = @("-3") + $xpy_args
         }
-        $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
-        Exit $process.ExitCode
+        Invoke-Application $python $xpy_args
     }
 }
 
 $found = (Get-Application "python*" | Where-Object {$_.name -match '^python[2-3]\.[0-9]+(\.exe)?$'})
 if (($null -ne $found) -and ($found.Length -ge 1)) {
     $python = $found[0]
-    $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
-    Exit $process.ExitCode
+    Invoke-Application $python $xpy_args
 }
 
 Write-Error "${PSCommandPath}: error: did not find python installed"